1865 lines · 68.7 KB · Java
RawDownload
/* * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *//* ******************************************************************************* * (C) Copyright IBM Corp. and others, 1996-2009 - All Rights Reserved         * *                                                                             * * The original version of this source code and documentation is copyrighted   * * and owned by IBM, These materials are provided under terms of a License     * * Agreement between IBM and Sun. This technology is protected by multiple     * * US and International patents. This notice and attribution to IBM may not    * * to removed.                                                                 * ******************************************************************************* */ package sun.text.normalizer; import java.text.ParsePosition;import java.util.Iterator;import java.util.TreeSet; /** * A mutable set of Unicode characters and multicharacter strings.  Objects of this class * represent <em>character classes</em> used in regular expressions. * A character specifies a subset of Unicode code points.  Legal * code points are U+0000 to U+10FFFF, inclusive. * * <p>The UnicodeSet class is not designed to be subclassed. * * <p><code>UnicodeSet</code> supports two APIs. The first is the * <em>operand</em> API that allows the caller to modify the value of * a <code>UnicodeSet</code> object. It conforms to Java 2's * <code>java.util.Set</code> interface, although * <code>UnicodeSet</code> does not actually implement that * interface. All methods of <code>Set</code> are supported, with the * modification that they take a character range or single character * instead of an <code>Object</code>, and they take a * <code>UnicodeSet</code> instead of a <code>Collection</code>.  The * operand API may be thought of in terms of boolean logic: a boolean * OR is implemented by <code>add</code>, a boolean AND is implemented * by <code>retain</code>, a boolean XOR is implemented by * <code>complement</code> taking an argument, and a boolean NOT is * implemented by <code>complement</code> with no argument.  In terms * of traditional set theory function names, <code>add</code> is a * union, <code>retain</code> is an intersection, <code>remove</code> * is an asymmetric difference, and <code>complement</code> with no * argument is a set complement with respect to the superset range * <code>MIN_VALUE-MAX_VALUE</code> * * <p>The second API is the * <code>applyPattern()</code>/<code>toPattern()</code> API from the * <code>java.text.Format</code>-derived classes.  Unlike the * methods that add characters, add categories, and control the logic * of the set, the method <code>applyPattern()</code> sets all * attributes of a <code>UnicodeSet</code> at once, based on a * string pattern. * * <p><b>Pattern syntax</b></p> * * Patterns are accepted by the constructors and the * <code>applyPattern()</code> methods and returned by the * <code>toPattern()</code> method.  These patterns follow a syntax * similar to that employed by version 8 regular expression character * classes.  Here are some simple examples: * * <blockquote> *   <table> *     <tr align="top"> *       <td nowrap valign="top" align="left"><code>[]</code></td> *       <td valign="top">No characters</td> *     </tr><tr align="top"> *       <td nowrap valign="top" align="left"><code>[a]</code></td> *       <td valign="top">The character 'a'</td> *     </tr><tr align="top"> *       <td nowrap valign="top" align="left"><code>[ae]</code></td> *       <td valign="top">The characters 'a' and 'e'</td> *     </tr> *     <tr> *       <td nowrap valign="top" align="left"><code>[a-e]</code></td> *       <td valign="top">The characters 'a' through 'e' inclusive, in Unicode code *       point order</td> *     </tr> *     <tr> *       <td nowrap valign="top" align="left"><code>[\\u4E01]</code></td> *       <td valign="top">The character U+4E01</td> *     </tr> *     <tr> *       <td nowrap valign="top" align="left"><code>[a{ab}{ac}]</code></td> *       <td valign="top">The character 'a' and the multicharacter strings &quot;ab&quot; and *       &quot;ac&quot;</td> *     </tr> *     <tr> *       <td nowrap valign="top" align="left"><code>[\p{Lu}]</code></td> *       <td valign="top">All characters in the general category Uppercase Letter</td> *     </tr> *   </table> * </blockquote> * * Any character may be preceded by a backslash in order to remove any special * meaning.  White space characters, as defined by UCharacterProperty.isRuleWhiteSpace(), are * ignored, unless they are escaped. * * <p>Property patterns specify a set of characters having a certain * property as defined by the Unicode standard.  Both the POSIX-like * "[:Lu:]" and the Perl-like syntax "\p{Lu}" are recognized.  For a * complete list of supported property patterns, see the User's Guide * for UnicodeSet at * <a href="http://www.icu-project.org/userguide/unicodeSet.html"> * http://www.icu-project.org/userguide/unicodeSet.html</a>. * Actual determination of property data is defined by the underlying * Unicode database as implemented by UCharacter. * * <p>Patterns specify individual characters, ranges of characters, and * Unicode property sets.  When elements are concatenated, they * specify their union.  To complement a set, place a '^' immediately * after the opening '['.  Property patterns are inverted by modifying * their delimiters; "[:^foo]" and "\P{foo}".  In any other location, * '^' has no special meaning. * * <p>Ranges are indicated by placing two a '-' between two * characters, as in "a-z".  This specifies the range of all * characters from the left to the right, in Unicode order.  If the * left character is greater than or equal to the * right character it is a syntax error.  If a '-' occurs as the first * character after the opening '[' or '[^', or if it occurs as the * last character before the closing ']', then it is taken as a * literal.  Thus "[a\\-b]", "[-ab]", and "[ab-]" all indicate the same * set of three characters, 'a', 'b', and '-'. * * <p>Sets may be intersected using the '&' operator or the asymmetric * set difference may be taken using the '-' operator, for example, * "[[:L:]&[\\u0000-\\u0FFF]]" indicates the set of all Unicode letters * with values less than 4096.  Operators ('&' and '|') have equal * precedence and bind left-to-right.  Thus * "[[:L:]-[a-z]-[\\u0100-\\u01FF]]" is equivalent to * "[[[:L:]-[a-z]]-[\\u0100-\\u01FF]]".  This only really matters for * difference; intersection is commutative. * * <table> * <tr valign=top><td nowrap><code>[a]</code><td>The set containing 'a' * <tr valign=top><td nowrap><code>[a-z]</code><td>The set containing 'a' * through 'z' and all letters in between, in Unicode order * <tr valign=top><td nowrap><code>[^a-z]</code><td>The set containing * all characters but 'a' through 'z', * that is, U+0000 through 'a'-1 and 'z'+1 through U+10FFFF * <tr valign=top><td nowrap><code>[[<em>pat1</em>][<em>pat2</em>]]</code> * <td>The union of sets specified by <em>pat1</em> and <em>pat2</em> * <tr valign=top><td nowrap><code>[[<em>pat1</em>]&[<em>pat2</em>]]</code> * <td>The intersection of sets specified by <em>pat1</em> and <em>pat2</em> * <tr valign=top><td nowrap><code>[[<em>pat1</em>]-[<em>pat2</em>]]</code> * <td>The asymmetric difference of sets specified by <em>pat1</em> and * <em>pat2</em> * <tr valign=top><td nowrap><code>[:Lu:] or \p{Lu}</code> * <td>The set of characters having the specified * Unicode property; in * this case, Unicode uppercase letters * <tr valign=top><td nowrap><code>[:^Lu:] or \P{Lu}</code> * <td>The set of characters <em>not</em> having the given * Unicode property * </table> * * <p><b>Warning</b>: you cannot add an empty string ("") to a UnicodeSet.</p> * * <p><b>Formal syntax</b></p> * * <blockquote> *   <table> *     <tr align="top"> *       <td nowrap valign="top" align="right"><code>pattern :=&nbsp; </code></td> *       <td valign="top"><code>('[' '^'? item* ']') | *       property</code></td> *     </tr> *     <tr align="top"> *       <td nowrap valign="top" align="right"><code>item :=&nbsp; </code></td> *       <td valign="top"><code>char | (char '-' char) | pattern-expr<br> *       </code></td> *     </tr> *     <tr align="top"> *       <td nowrap valign="top" align="right"><code>pattern-expr :=&nbsp; </code></td> *       <td valign="top"><code>pattern | pattern-expr pattern | *       pattern-expr op pattern<br> *       </code></td> *     </tr> *     <tr align="top"> *       <td nowrap valign="top" align="right"><code>op :=&nbsp; </code></td> *       <td valign="top"><code>'&amp;' | '-'<br> *       </code></td> *     </tr> *     <tr align="top"> *       <td nowrap valign="top" align="right"><code>special :=&nbsp; </code></td> *       <td valign="top"><code>'[' | ']' | '-'<br> *       </code></td> *     </tr> *     <tr align="top"> *       <td nowrap valign="top" align="right"><code>char :=&nbsp; </code></td> *       <td valign="top"><em>any character that is not</em><code> special<br> *       | ('\\' </code><em>any character</em><code>)<br> *       | ('&#92;u' hex hex hex hex)<br> *       </code></td> *     </tr> *     <tr align="top"> *       <td nowrap valign="top" align="right"><code>hex :=&nbsp; </code></td> *       <td valign="top"><em>any character for which *       </em><code>Character.digit(c, 16)</code><em> *       returns a non-negative result</em></td> *     </tr> *     <tr> *       <td nowrap valign="top" align="right"><code>property :=&nbsp; </code></td> *       <td valign="top"><em>a Unicode property set pattern</td> *     </tr> *   </table> *   <br> *   <table border="1"> *     <tr> *       <td>Legend: <table> *         <tr> *           <td nowrap valign="top"><code>a := b</code></td> *           <td width="20" valign="top">&nbsp; </td> *           <td valign="top"><code>a</code> may be replaced by <code>b</code> </td> *         </tr> *         <tr> *           <td nowrap valign="top"><code>a?</code></td> *           <td valign="top"></td> *           <td valign="top">zero or one instance of <code>a</code><br> *           </td> *         </tr> *         <tr> *           <td nowrap valign="top"><code>a*</code></td> *           <td valign="top"></td> *           <td valign="top">one or more instances of <code>a</code><br> *           </td> *         </tr> *         <tr> *           <td nowrap valign="top"><code>a | b</code></td> *           <td valign="top"></td> *           <td valign="top">either <code>a</code> or <code>b</code><br> *           </td> *         </tr> *         <tr> *           <td nowrap valign="top"><code>'a'</code></td> *           <td valign="top"></td> *           <td valign="top">the literal string between the quotes </td> *         </tr> *       </table> *       </td> *     </tr> *   </table> * </blockquote> * <p>To iterate over contents of UnicodeSet, use UnicodeSetIterator class. * * @author Alan Liu * @stable ICU 2.0 * @see UnicodeSetIterator */public class UnicodeSet implements UnicodeMatcher {     private static final int LOW = 0x000000; // LOW <= all valid values. ZERO for codepoints    private static final int HIGH = 0x110000; // HIGH > all valid values. 10000 for code units.                                             // 110000 for codepoints     /**     * Minimum value that can be stored in a UnicodeSet.     * @stable ICU 2.0     */    public static final int MIN_VALUE = LOW;     /**     * Maximum value that can be stored in a UnicodeSet.     * @stable ICU 2.0     */    public static final int MAX_VALUE = HIGH - 1;     private int len;      // length used; list may be longer to minimize reallocs    private int[] list;   // MUST be terminated with HIGH    private int[] rangeList; // internal buffer    private int[] buffer; // internal buffer     // NOTE: normally the field should be of type SortedSet; but that is missing a public clone!!    // is not private so that UnicodeSetIterator can get access    TreeSet strings = new TreeSet();     /**     * The pattern representation of this set.  This may not be the     * most economical pattern.  It is the pattern supplied to     * applyPattern(), with variables substituted and whitespace     * removed.  For sets constructed without applyPattern(), or     * modified using the non-pattern API, this string will be null,     * indicating that toPattern() must generate a pattern     * representation from the inversion list.     */    private String pat = null;     private static final int START_EXTRA = 16;         // initial storage. Must be >= 0    private static final int GROW_EXTRA = START_EXTRA; // extra amount for growth. Must be >= 0     /**     * A set of all characters _except_ the second through last characters of     * certain ranges.  These ranges are ranges of characters whose     * properties are all exactly alike, e.g. CJK Ideographs from     * U+4E00 to U+9FA5.     */    private static UnicodeSet INCLUSIONS[] = null;     //----------------------------------------------------------------    // Public API    //----------------------------------------------------------------     /**     * Constructs an empty set.     * @stable ICU 2.0     */    public UnicodeSet() {        list = new int[1 + START_EXTRA];        list[len++] = HIGH;    }     /**     * Constructs a set containing the given range. If <code>end >     * start</code> then an empty set is created.     *     * @param start first character, inclusive, of range     * @param end last character, inclusive, of range     * @stable ICU 2.0     */    public UnicodeSet(int start, int end) {        this();        complement(start, end);    }     /**     * Constructs a set from the given pattern.  See the class description     * for the syntax of the pattern language.  Whitespace is ignored.     * @param pattern a string specifying what characters are in the set     * @exception java.lang.IllegalArgumentException if the pattern contains     * a syntax error.     * @stable ICU 2.0     */    public UnicodeSet(String pattern) {        this();        applyPattern(pattern, null, null, IGNORE_SPACE);    }     /**     * Make this object represent the same set as <code>other</code>.     * @param other a <code>UnicodeSet</code> whose value will be     * copied to this object     * @stable ICU 2.0     */    public UnicodeSet set(UnicodeSet other) {        list = (int[]) other.list.clone();        len = other.len;        pat = other.pat;        strings = (TreeSet)other.strings.clone();        return this;    }     /**     * Modifies this set to represent the set specified by the given pattern.     * See the class description for the syntax of the pattern language.     * Whitespace is ignored.     * @param pattern a string specifying what characters are in the set     * @exception java.lang.IllegalArgumentException if the pattern     * contains a syntax error.     * @stable ICU 2.0     */    public final UnicodeSet applyPattern(String pattern) {        return applyPattern(pattern, null, null, IGNORE_SPACE);    }     /**     * Append the <code>toPattern()</code> representation of a     * string to the given <code>StringBuffer</code>.     */    private static void _appendToPat(StringBuffer buf, String s, boolean escapeUnprintable) {        for (int i = 0; i < s.length(); i += UTF16.getCharCount(i)) {            _appendToPat(buf, UTF16.charAt(s, i), escapeUnprintable);        }    }     /**     * Append the <code>toPattern()</code> representation of a     * character to the given <code>StringBuffer</code>.     */    private static void _appendToPat(StringBuffer buf, int c, boolean escapeUnprintable) {        if (escapeUnprintable && Utility.isUnprintable(c)) {            // Use hex escape notation (<backslash>uxxxx or <backslash>Uxxxxxxxx) for anything            // unprintable            if (Utility.escapeUnprintable(buf, c)) {                return;            }        }        // Okay to let ':' pass through        switch (c) {        case '[': // SET_OPEN:        case ']': // SET_CLOSE:        case '-': // HYPHEN:        case '^': // COMPLEMENT:        case '&': // INTERSECTION:        case '\\': //BACKSLASH:        case '{':        case '}':        case '$':        case ':':            buf.append('\\');            break;        default:            // Escape whitespace            if (UCharacterProperty.isRuleWhiteSpace(c)) {                buf.append('\\');            }            break;        }        UTF16.append(buf, c);    }     /**     * Append a string representation of this set to result.  This will be     * a cleaned version of the string passed to applyPattern(), if there     * is one.  Otherwise it will be generated.     */    private StringBuffer _toPattern(StringBuffer result,                                    boolean escapeUnprintable) {        if (pat != null) {            int i;            int backslashCount = 0;            for (i=0; i<pat.length(); ) {                int c = UTF16.charAt(pat, i);                i += UTF16.getCharCount(c);                if (escapeUnprintable && Utility.isUnprintable(c)) {                    // If the unprintable character is preceded by an odd                    // number of backslashes, then it has been escaped.                    // Before unescaping it, we delete the final                    // backslash.                    if ((backslashCount % 2) == 1) {                        result.setLength(result.length() - 1);                    }                    Utility.escapeUnprintable(result, c);                    backslashCount = 0;                } else {                    UTF16.append(result, c);                    if (c == '\\') {                        ++backslashCount;                    } else {                        backslashCount = 0;                    }                }            }            return result;        }         return _generatePattern(result, escapeUnprintable, true);    }     /**     * Generate and append a string representation of this set to result.     * This does not use this.pat, the cleaned up copy of the string     * passed to applyPattern().     * @param includeStrings if false, doesn't include the strings.     * @stable ICU 3.8     */    public StringBuffer _generatePattern(StringBuffer result,                                         boolean escapeUnprintable, boolean includeStrings) {        result.append('[');         int count = getRangeCount();         // If the set contains at least 2 intervals and includes both        // MIN_VALUE and MAX_VALUE, then the inverse representation will        // be more economical.        if (count > 1 &&            getRangeStart(0) == MIN_VALUE &&            getRangeEnd(count-1) == MAX_VALUE) {             // Emit the inverse            result.append('^');             for (int i = 1; i < count; ++i) {                int start = getRangeEnd(i-1)+1;                int end = getRangeStart(i)-1;

Lines 1–500 of 1865.