/* * 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 "ab" and * "ac"</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 := </code></td> * <td valign="top"><code>('[' '^'? item* ']') | * property</code></td> * </tr> * <tr align="top"> * <td nowrap valign="top" align="right"><code>item := </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 := </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 := </code></td> * <td valign="top"><code>'&' | '-'<br> * </code></td> * </tr> * <tr align="top"> * <td nowrap valign="top" align="right"><code>special := </code></td> * <td valign="top"><code>'[' | ']' | '-'<br> * </code></td> * </tr> * <tr align="top"> * <td nowrap valign="top" align="right"><code>char := </code></td> * <td valign="top"><em>any character that is not</em><code> special<br> * | ('\\' </code><em>any character</em><code>)<br> * | ('\u' hex hex hex hex)<br> * </code></td> * </tr> * <tr align="top"> * <td nowrap valign="top" align="right"><code>hex := </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 := </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"> </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. Load more
/* * 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 "ab" and * "ac"</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 := </code></td> * <td valign="top"><code>('[' '^'? item* ']') | * property</code></td> * </tr> * <tr align="top"> * <td nowrap valign="top" align="right"><code>item := </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 := </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 := </code></td> * <td valign="top"><code>'&' | '-'<br> * </code></td> * </tr> * <tr align="top"> * <td nowrap valign="top" align="right"><code>special := </code></td> * <td valign="top"><code>'[' | ']' | '-'<br> * </code></td> * </tr> * <tr align="top"> * <td nowrap valign="top" align="right"><code>char := </code></td> * <td valign="top"><em>any character that is not</em><code> special<br> * | ('\\' </code><em>any character</em><code>)<br> * | ('\u' hex hex hex hex)<br> * </code></td> * </tr> * <tr align="top"> * <td nowrap valign="top" align="right"><code>hex := </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 := </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"> </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;