2 //#if defined(FOUNDATION10) || defined(J2SE13)
5 *******************************************************************************
6 * Copyright (C) 1996-2009, International Business Machines Corporation and *
7 * others. All Rights Reserved. *
8 *******************************************************************************
10 package com.ibm.icu.dev.test.util;
12 import java.io.PrintWriter;
13 import java.io.StringWriter;
14 import java.text.ParsePosition;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Comparator;
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.List;
22 import java.util.TreeMap;
23 import java.util.regex.Pattern;
25 import com.ibm.icu.dev.test.util.CollectionUtilities.InverseMatcher;
26 import com.ibm.icu.dev.test.util.CollectionUtilities.ObjectMatcher;
27 import com.ibm.icu.impl.Utility;
28 import com.ibm.icu.text.SymbolTable;
29 import com.ibm.icu.text.UTF16;
30 import com.ibm.icu.text.UnicodeMatcher;
31 import com.ibm.icu.text.UnicodeSet;
32 import com.ibm.icu.text.UnicodeSetIterator;
34 public abstract class UnicodeProperty extends UnicodeLabel {
36 public static boolean DEBUG = false;
38 public static String CHECK_NAME = "FC_NFKC_Closure";
40 public static int CHECK_VALUE = 0x037A;
44 private String firstNameAlias = null;
48 private Map valueToFirstValueAlias = null;
51 * Name: Unicode_1_Name Name: ISO_Comment Name: Name Name: Unicode_1_Name
55 public static final int UNKNOWN = 0, BINARY = 2, EXTENDED_BINARY = 3,
56 ENUMERATED = 4, EXTENDED_ENUMERATED = 5, CATALOG = 6,
57 EXTENDED_CATALOG = 7, MISC = 8, EXTENDED_MISC = 9, STRING = 10,
58 EXTENDED_STRING = 11, NUMERIC = 12, EXTENDED_NUMERIC = 13,
59 START_TYPE = 2, LIMIT_TYPE = 14, EXTENDED_MASK = 1,
60 CORE_MASK = ~EXTENDED_MASK, BINARY_MASK = (1 << BINARY)
61 | (1 << EXTENDED_BINARY), STRING_MASK = (1 << STRING)
62 | (1 << EXTENDED_STRING),
63 STRING_OR_MISC_MASK = (1 << STRING) | (1 << EXTENDED_STRING)
64 | (1 << MISC) | (1 << EXTENDED_MISC),
65 ENUMERATED_OR_CATALOG_MASK = (1 << ENUMERATED)
66 | (1 << EXTENDED_ENUMERATED) | (1 << CATALOG)
67 | (1 << EXTENDED_CATALOG);
69 private static final String[] TYPE_NAMES = { "Unknown", "Unknown",
70 "Binary", "Extended Binary", "Enumerated", "Extended Enumerated",
71 "Catalog", "Extended Catalog", "Miscellaneous",
72 "Extended Miscellaneous", "String", "Extended String", "Numeric",
73 "Extended Numeric", };
75 public static String getTypeName(int propType) {
76 return TYPE_NAMES[propType];
79 public final String getName() {
83 public final int getType() {
87 public final boolean isType(int mask) {
88 return ((1 << type) & mask) != 0;
91 protected final void setName(String string) {
93 throw new IllegalArgumentException("Name must not be null");
97 protected final void setType(int i) {
101 public String getVersion() {
102 return _getVersion();
105 public String getValue(int codepoint) {
106 if (DEBUG && CHECK_VALUE == codepoint && CHECK_NAME.equals(getName())) {
107 String value = _getValue(codepoint);
108 System.out.println(getName() + "(" + Utility.hex(codepoint) + "):"
109 + (getType() == STRING ? Utility.hex(value) : value));
112 return _getValue(codepoint);
115 // public String getValue(int codepoint, boolean isShort) {
116 // return getValue(codepoint);
119 public List getNameAliases(List result) {
121 result = new ArrayList(1);
122 return _getNameAliases(result);
125 public List getValueAliases(String valueAlias, List result) {
127 result = new ArrayList(1);
128 result = _getValueAliases(valueAlias, result);
129 if (!result.contains(valueAlias)) { // FIX && type < NUMERIC
130 result = _getValueAliases(valueAlias, result); // for debugging
131 throw new IllegalArgumentException("Internal error: " + getName()
132 + " doesn't contain " + valueAlias + ": "
133 + new BagFormatter().join(result));
138 public List getAvailableValues(List result) {
140 result = new ArrayList(1);
141 return _getAvailableValues(result);
144 protected abstract String _getVersion();
146 protected abstract String _getValue(int codepoint);
148 protected abstract List _getNameAliases(List result);
150 protected abstract List _getValueAliases(String valueAlias, List result);
152 protected abstract List _getAvailableValues(List result);
155 public final List getNameAliases() {
156 return getNameAliases(null);
159 public final List getValueAliases(String valueAlias) {
160 return getValueAliases(valueAlias, null);
163 public final List getAvailableValues() {
164 return getAvailableValues(null);
167 public final String getValue(int codepoint, boolean getShortest) {
168 String result = getValue(codepoint);
169 if (type >= MISC || result == null || !getShortest)
171 return getFirstValueAlias(result);
174 public final String getFirstNameAlias() {
175 if (firstNameAlias == null) {
176 firstNameAlias = (String) getNameAliases().get(0);
178 return firstNameAlias;
181 public final String getFirstValueAlias(String value) {
182 if (valueToFirstValueAlias == null)
183 _getFirstValueAliasCache();
184 return (String) valueToFirstValueAlias.get(value);
187 private void _getFirstValueAliasCache() {
189 maxFirstValueAliasWidth = 0;
190 valueToFirstValueAlias = new HashMap(1);
191 Iterator it = getAvailableValues().iterator();
192 while (it.hasNext()) {
193 String value = (String) it.next();
194 String first = (String) getValueAliases(value).get(0);
195 if (first == null) { // internal error
196 throw new IllegalArgumentException(
197 "Value not in value aliases: " + value);
199 if (DEBUG && CHECK_NAME.equals(getName())) {
200 System.out.println("First Alias: " + getName() + ": " + value
202 + new BagFormatter().join(getValueAliases(value)));
204 valueToFirstValueAlias.put(value, first);
205 if (value.length() > maxValueWidth) {
206 maxValueWidth = value.length();
208 if (first.length() > maxFirstValueAliasWidth) {
209 maxFirstValueAliasWidth = first.length();
214 private int maxValueWidth = -1;
216 private int maxFirstValueAliasWidth = -1;
218 public int getMaxWidth(boolean getShortest) {
219 if (maxValueWidth < 0)
220 _getFirstValueAliasCache();
222 return maxFirstValueAliasWidth;
223 return maxValueWidth;
226 public final UnicodeSet getSet(String propertyValue) {
227 return getSet(propertyValue, null);
230 public final UnicodeSet getSet(PatternMatcher matcher) {
231 return getSet(matcher, null);
234 public final UnicodeSet getSet(String propertyValue, UnicodeSet result) {
235 return getSet(new SimpleMatcher(propertyValue,
236 isType(STRING_OR_MISC_MASK) ? null : PROPERTY_COMPARATOR),
240 private UnicodeMap unicodeMap = null;
242 public static final String UNUSED = "??";
244 public final UnicodeSet getSet(PatternMatcher matcher, UnicodeSet result) {
246 result = new UnicodeSet();
247 if (isType(STRING_OR_MISC_MASK)) {
248 for (int i = 0; i <= 0x10FFFF; ++i) {
249 String value = getValue(i);
250 if (value != null && matcher.matches(value)) {
256 List temp = new ArrayList(1); // to avoid reallocating...
257 UnicodeMap um = getUnicodeMap_internal();
258 Iterator it = um.getAvailableValues(null).iterator();
259 main: while (it.hasNext()) {
260 String value = (String) it.next();
262 Iterator it2 = getValueAliases(value, temp).iterator();
263 while (it2.hasNext()) {
264 String value2 = (String) it2.next();
265 // System.out.println("Values:" + value2);
266 if (matcher.matches(value2)
267 || matcher.matches(toSkeleton(value2))) {
268 um.getSet(value, result);
277 * public UnicodeSet getMatchSet(UnicodeSet result) { if (result == null)
278 * result = new UnicodeSet(); addAll(matchIterator, result); return result; }
280 * public void setMatchSet(UnicodeSet set) { matchIterator = new
281 * UnicodeSetIterator(set); }
285 * Utility for debugging
287 public static String getStack() {
288 Exception e = new Exception();
289 StringWriter sw = new StringWriter();
290 PrintWriter pw = new PrintWriter(sw);
291 e.printStackTrace(pw);
293 return "Showing Stack with fake " + sw.getBuffer().toString();
296 // TODO use this instead of plain strings
297 public static class Name implements Comparable {
298 private String skeleton;
300 private String pretty;
302 public final int RAW = 0, TITLE = 1, NORMAL = 2;
304 public Name(String name, int style) {
308 skeleton = pretty = name;
310 pretty = regularize(name, style == TITLE);
311 skeleton = toSkeleton(pretty);
315 public int compareTo(Object o) {
316 return skeleton.compareTo(((Name) o).skeleton);
319 public boolean equals(Object o) {
320 return skeleton.equals(((Name) o).skeleton);
323 public int hashCode() {
324 return skeleton.hashCode();
327 public String toString() {
333 * @return the unicode map
335 public UnicodeMap getUnicodeMap() {
336 return getUnicodeMap(false);
340 * @return the unicode map
342 public UnicodeMap getUnicodeMap(boolean getShortest) {
344 return (UnicodeMap) getUnicodeMap_internal().cloneAsThawed();
345 UnicodeMap result = new UnicodeMap();
346 for (int i = 0; i <= 0x10FFFF; ++i) {
347 // if (DEBUG && i == 0x41) System.out.println(i + "\t" +
349 String value = getValue(i, true);
350 result.put(i, value);
356 * @return the unicode map
358 protected UnicodeMap getUnicodeMap_internal() {
359 if (unicodeMap == null)
360 unicodeMap = _getUnicodeMap();
364 protected UnicodeMap _getUnicodeMap() {
365 UnicodeMap result = new UnicodeMap();
366 HashMap myIntern = new HashMap();
367 for (int i = 0; i <= 0x10FFFF; ++i) {
368 // if (DEBUG && i == 0x41) System.out.println(i + "\t" +
370 String value = getValue(i);
371 String iValue = (String) myIntern.get(value);
373 myIntern.put(value, iValue = value);
374 result.put(i, iValue);
377 for (int i = 0; i <= 0x10FFFF; ++i) {
378 // if (DEBUG && i == 0x41) System.out.println(i + "\t" +
380 String value = getValue(i);
381 String resultValue = (String) result.getValue(i);
382 if (!value.equals(resultValue)) {
383 throw new RuntimeException("Value failure at: "
388 if (DEBUG && CHECK_NAME.equals(getName())) {
389 System.out.println(getName() + ":\t" + getClass().getName() + "\t"
391 System.out.println(getStack());
392 System.out.println(result);
398 * Really ought to create a Collection UniqueList, that forces uniqueness.
401 public static Collection addUnique(Object obj, Collection result) {
402 if (obj != null && !result.contains(obj))
408 * Utility for managing property & non-string value aliases
410 public static final Comparator PROPERTY_COMPARATOR = new Comparator() {
411 public int compare(Object o1, Object o2) {
412 return compareNames((String) o1, (String) o2);
417 * Utility for managing property & non-string value aliases
421 public static boolean equalNames(String a, String b) {
426 return toSkeleton(a).equals(toSkeleton(b));
430 * Utility for managing property & non-string value aliases
433 public static int compareNames(String a, String b) {
440 return toSkeleton(a).compareTo(toSkeleton(b));
444 * Utility for managing property & non-string value aliases
446 // TODO account for special names, tibetan, hangul
447 public static String toSkeleton(String source) {
450 StringBuffer skeletonBuffer = new StringBuffer();
451 boolean gotOne = false;
452 // remove spaces, '_', '-'
453 // we can do this with char, since no surrogates are involved
454 for (int i = 0; i < source.length(); ++i) {
455 char ch = source.charAt(i);
456 if (i > 0 && (ch == '_' || ch == ' ' || ch == '-')) {
459 char ch2 = Character.toLowerCase(ch);
462 skeletonBuffer.append(ch2);
464 skeletonBuffer.append(ch);
469 return source; // avoid string creation
470 return skeletonBuffer.toString();
473 // get the name skeleton
474 public static String toNameSkeleton(String source) {
477 StringBuffer result = new StringBuffer();
478 // remove spaces, medial '-'
479 // we can do this with char, since no surrogates are involved
480 for (int i = 0; i < source.length(); ++i) {
481 char ch = source.charAt(i);
482 if (('0' <= ch && ch <= '9') || ('A' <= ch && ch <= 'Z')
483 || ch == '<' || ch == '>') {
485 } else if (ch == ' ') {
487 } else if (ch == '-') {
488 // only copy non-medials AND trailing O-E
490 || i == source.length() - 1
491 || source.charAt(i - 1) == ' '
492 || source.charAt(i + 1) == ' '
493 || (i == source.length() - 2
494 && source.charAt(i - 1) == 'O' && source
495 .charAt(i + 1) == 'E')) {
496 System.out.println("****** EXCEPTION " + source);
499 // otherwise don't copy
501 throw new IllegalArgumentException("Illegal Name Char: U+"
502 + Utility.hex(ch) + ", " + ch);
505 return result.toString();
509 * These routines use the Java functions, because they only need to act on
510 * ASCII Changes space, - into _, inserts _ between lower and UPPER.
512 public static String regularize(String source, boolean titlecaseStart) {
516 * if (source.equals("noBreak")) { // HACK if (titlecaseStart) return
517 * "NoBreak"; return source; }
519 StringBuffer result = new StringBuffer();
521 boolean haveFirstCased = true;
522 for (int i = 0; i < source.length(); ++i) {
523 char c = source.charAt(i);
524 if (c == ' ' || c == '-' || c == '_') {
526 haveFirstCased = true;
529 haveFirstCased = true;
530 int cat = Character.getType(c);
531 if (lastCat == Character.LOWERCASE_LETTER
532 && cat == Character.UPPERCASE_LETTER) {
536 && (cat == Character.LOWERCASE_LETTER
537 || cat == Character.TITLECASE_LETTER || cat == Character.UPPERCASE_LETTER)) {
538 if (titlecaseStart) {
539 c = Character.toUpperCase(c);
541 haveFirstCased = false;
546 return result.toString();
550 * Utility function for comparing codepoint to string without generating new
555 * @return true if the codepoint equals the string
557 public static final boolean equals(int codepoint, String other) {
558 if (other.length() == 1) {
559 return codepoint == other.charAt(0);
561 if (other.length() == 2) {
562 return other.equals(UTF16.valueOf(codepoint));
568 * Utility that should be on UnicodeSet
573 static public void addAll(UnicodeSetIterator source, UnicodeSet result) {
574 while (source.nextRange()) {
575 if (source.codepoint == UnicodeSetIterator.IS_STRING) {
576 result.add(source.string);
578 result.add(source.codepoint, source.codepointEnd);
584 * Really ought to create a Collection UniqueList, that forces uniqueness.
587 public static Collection addAllUnique(Collection source, Collection result) {
588 for (Iterator it = source.iterator(); it.hasNext();) {
589 addUnique(it.next(), result);
595 * Really ought to create a Collection UniqueList, that forces uniqueness.
598 public static Collection addAllUnique(Object[] source, Collection result) {
599 for (int i = 0; i < source.length; ++i) {
600 addUnique(source[i], result);
605 static public class Factory {
606 static boolean DEBUG = false;
608 Map canonicalNames = new TreeMap();
610 Map skeletonNames = new TreeMap();
612 Map propertyCache = new HashMap(1);
614 public final Factory add(UnicodeProperty sp) {
615 canonicalNames.put(sp.getName(), sp);
616 List c = sp.getNameAliases(new ArrayList(1));
617 Iterator it = c.iterator();
618 while (it.hasNext()) {
619 skeletonNames.put(toSkeleton((String) it.next()), sp);
624 public final UnicodeProperty getProperty(String propertyAlias) {
625 return (UnicodeProperty) skeletonNames
626 .get(toSkeleton(propertyAlias));
629 public final List getAvailableNames() {
630 return getAvailableNames(null);
633 public final List getAvailableNames(List result) {
635 result = new ArrayList(1);
636 Iterator it = canonicalNames.keySet().iterator();
637 while (it.hasNext()) {
638 addUnique(it.next(), result);
643 public final List getAvailableNames(int propertyTypeMask) {
644 return getAvailableNames(propertyTypeMask, null);
647 public final List getAvailableNames(int propertyTypeMask, List result) {
649 result = new ArrayList(1);
650 Iterator it = canonicalNames.keySet().iterator();
651 while (it.hasNext()) {
652 String item = (String) it.next();
653 UnicodeProperty property = getProperty(item);
655 System.out.println("Properties: " + item + ","
656 + property.getType());
657 if (!property.isType(propertyTypeMask)) {
658 // System.out.println("Masking: " + property.getType() + ","
659 // + propertyTypeMask);
662 addUnique(property.getName(), result);
667 InversePatternMatcher inverseMatcher = new InversePatternMatcher();
670 * Format is: propname ('=' | '!=') propvalue ( '|' propValue )*
672 public final UnicodeSet getSet(String propAndValue,
673 PatternMatcher matcher, UnicodeSet result) {
674 int equalPos = propAndValue.indexOf('=');
675 String prop = propAndValue.substring(0, equalPos);
676 String value = propAndValue.substring(equalPos + 1);
677 boolean negative = false;
678 if (prop.endsWith("!")) {
679 prop = prop.substring(0, prop.length() - 1);
683 UnicodeProperty up = getProperty(prop);
684 if (matcher == null) {
685 matcher = new SimpleMatcher(value, up
686 .isType(STRING_OR_MISC_MASK) ? null
687 : PROPERTY_COMPARATOR);
690 inverseMatcher.set(matcher);
691 matcher = inverseMatcher;
693 return up.getSet(matcher.set(value), result);
696 public final UnicodeSet getSet(String propAndValue,
697 PatternMatcher matcher) {
698 return getSet(propAndValue, matcher, null);
701 public final UnicodeSet getSet(String propAndValue) {
702 return getSet(propAndValue, null, null);
705 public final SymbolTable getSymbolTable(String prefix) {
706 return new PropertySymbolTable(prefix);
709 private class MyXSymbolTable extends UnicodeSet.XSymbolTable {
710 public boolean applyPropertyAlias(String propertyName,
711 String propertyValue, UnicodeSet result) {
713 System.out.println(propertyName + "=" + propertyValue);
714 UnicodeProperty prop = getProperty(propertyName);
718 UnicodeSet x = prop.getSet(propertyValue, result);
719 return x.size() != 0;
723 public final UnicodeSet.XSymbolTable getXSymbolTable() {
724 return new MyXSymbolTable();
727 private class PropertySymbolTable implements SymbolTable {
728 static final boolean DEBUG = false;
730 private String prefix;
732 RegexMatcher regexMatcher = new RegexMatcher();
734 PropertySymbolTable(String prefix) {
735 this.prefix = prefix;
738 public char[] lookup(String s) {
740 System.out.println("\t(" + prefix + ")Looking up " + s);
741 // ensure, again, that prefix matches
742 int start = prefix.length();
743 if (!s.regionMatches(true, 0, prefix, 0, start))
746 int pos = s.indexOf(':', start);
747 if (pos < 0) { // should never happen
748 throw new IllegalArgumentException(
749 "Internal Error: missing =: " + s + "\r\n");
751 UnicodeProperty prop = getProperty(s.substring(start, pos));
753 throw new IllegalArgumentException("Invalid Property in: "
754 + s + "\r\nUse " + showSet(getAvailableNames()));
756 String value = s.substring(pos + 1);
758 if (value.startsWith("\u00AB")) { // regex!
759 set = prop.getSet(regexMatcher.set(value.substring(1, value
762 set = prop.getSet(value);
764 if (set.size() == 0) {
765 throw new IllegalArgumentException(
766 "Empty Property-Value in: " + s + "\r\nUse "
767 + showSet(prop.getAvailableValues()));
770 System.out.println("\t(" + prefix + ")Returning "
771 + set.toPattern(true));
772 return set.toPattern(true).toCharArray(); // really ugly
775 private String showSet(List list) {
776 StringBuffer result = new StringBuffer("[");
777 boolean first = true;
778 for (Iterator it = list.iterator(); it.hasNext();) {
783 result.append(it.next().toString());
786 return result.toString();
789 public UnicodeMatcher lookupMatcher(int ch) {
793 public String parseReference(String text, ParsePosition pos,
796 System.out.println("\t(" + prefix + ")Parsing <"
797 + text.substring(pos.getIndex(), limit) + ">");
798 int start = pos.getIndex();
799 // ensure that it starts with 'prefix'
801 .regionMatches(true, start, prefix, 0, prefix.length()))
803 start += prefix.length();
804 // now see if it is of the form identifier:identifier
805 int i = getIdentifier(text, start, limit);
808 String prop = text.substring(start, i);
809 String value = "true";
811 if (text.charAt(i) == ':') {
813 if (text.charAt(i + 1) == '\u00AB') { // regular
815 j = text.indexOf('\u00BB', i + 2) + 1; // include
821 j = getIdentifier(text, i + 1, limit);
823 value = text.substring(i + 1, j);
829 System.out.println("\t(" + prefix + ")Parsed <" + prop
830 + ">=<" + value + ">");
831 return prefix + prop + ":" + value;
834 private int getIdentifier(String text, int start, int limit) {
836 System.out.println("\tGetID <"
837 + text.substring(start, limit) + ">");
840 for (i = start; i < limit; i += UTF16.getCharCount(cp)) {
841 cp = UTF16.charAt(text, i);
842 if (!com.ibm.icu.lang.UCharacter
843 .isUnicodeIdentifierPart(cp)
849 System.out.println("\tGotID <" + text.substring(start, i)
856 public static class FilteredProperty extends UnicodeProperty {
857 private UnicodeProperty property;
859 protected StringFilter filter;
861 protected UnicodeSetIterator matchIterator = new UnicodeSetIterator(
862 new UnicodeSet(0, 0x10FFFF));
864 protected HashMap backmap;
866 boolean allowValueAliasCollisions = false;
868 public FilteredProperty(UnicodeProperty property, StringFilter filter) {
869 this.property = property;
870 this.filter = filter;
873 public StringFilter getFilter() {
877 public UnicodeProperty setFilter(StringFilter filter) {
878 this.filter = filter;
882 List temp = new ArrayList(1);
884 public List _getAvailableValues(List result) {
886 return filter.addUnique(property.getAvailableValues(temp), result);
889 public List _getNameAliases(List result) {
891 return filter.addUnique(property.getNameAliases(temp), result);
894 public String _getValue(int codepoint) {
895 return filter.remap(property.getValue(codepoint));
898 public List _getValueAliases(String valueAlias, List result) {
899 if (backmap == null) {
900 backmap = new HashMap(1);
902 Iterator it = property.getAvailableValues(temp).iterator();
903 while (it.hasNext()) {
904 String item = (String) it.next();
905 String mappedItem = filter.remap(item);
906 if (backmap.get(mappedItem) != null
907 && !allowValueAliasCollisions) {
908 throw new IllegalArgumentException(
909 "Filter makes values collide! " + item + ", "
912 backmap.put(mappedItem, item);
915 valueAlias = (String) backmap.get(valueAlias);
917 return filter.addUnique(property.getValueAliases(valueAlias, temp),
921 public String _getVersion() {
922 return property.getVersion();
925 public boolean isAllowValueAliasCollisions() {
926 return allowValueAliasCollisions;
929 public FilteredProperty setAllowValueAliasCollisions(boolean b) {
930 allowValueAliasCollisions = b;
936 public static abstract class StringFilter implements Cloneable {
937 public abstract String remap(String original);
939 public final List addUnique(Collection source, List result) {
941 result = new ArrayList(1);
942 Iterator it = source.iterator();
943 while (it.hasNext()) {
944 UnicodeProperty.addUnique(remap((String) it.next()), result);
949 * public Object clone() { try { return super.clone(); } catch
950 * (CloneNotSupportedException e) { throw new
951 * IllegalStateException("Should never happen."); } }
955 public static class MapFilter extends StringFilter {
956 private Map valueMap;
958 public MapFilter(Map valueMap) {
959 this.valueMap = valueMap;
962 public String remap(String original) {
963 Object changed = valueMap.get(original);
964 return changed == null ? original : (String) changed;
967 public Map getMap() {
972 public interface PatternMatcher extends ObjectMatcher {
973 public PatternMatcher set(String pattern);
976 public static class InversePatternMatcher extends InverseMatcher implements
978 PatternMatcher other;
980 public PatternMatcher set(PatternMatcher toInverse) {
985 public boolean matches(Object value) {
986 return !other.matches(value);
989 public PatternMatcher set(String pattern) {
995 public static class SimpleMatcher implements PatternMatcher {
996 Comparator comparator;
1000 public SimpleMatcher(String pattern, Comparator comparator) {
1001 this.comparator = comparator;
1002 this.pattern = pattern;
1005 public boolean matches(Object value) {
1006 if (comparator == null)
1007 return pattern.equals(value);
1008 return comparator.compare(pattern, value) == 0;
1011 public PatternMatcher set(String pattern) {
1012 this.pattern = pattern;
1017 public static class RegexMatcher implements UnicodeProperty.PatternMatcher {
1018 private java.util.regex.Matcher matcher;
1020 public UnicodeProperty.PatternMatcher set(String pattern) {
1021 matcher = Pattern.compile(pattern).matcher("");
1025 public boolean matches(Object value) {
1026 matcher.reset(value.toString());
1027 return matcher.matches();
1031 public static abstract class BaseProperty extends UnicodeProperty {
1032 protected List propertyAliases = new ArrayList(1);
1034 protected Map toValueAliases;
1036 protected String version;
1038 public BaseProperty setMain(String alias, String shortAlias,
1039 int propertyType, String version) {
1041 setType(propertyType);
1042 propertyAliases.add(shortAlias);
1043 propertyAliases.add(alias);
1044 this.version = version;
1048 public String _getVersion() {
1052 public List _getNameAliases(List result) {
1053 addAllUnique(propertyAliases, result);
1057 public BaseProperty addValueAliases(String[][] valueAndAlternates,
1058 boolean errorIfCant) {
1059 if (toValueAliases == null)
1061 for (int i = 0; i < valueAndAlternates.length; ++i) {
1062 for (int j = 1; j < valueAndAlternates[0].length; ++j) {
1063 addValueAlias(valueAndAlternates[i][0],
1064 valueAndAlternates[i][j], errorIfCant);
1070 public void addValueAlias(String value, String valueAlias,
1071 boolean errorIfCant) {
1072 List result = (List) toValueAliases.get(value);
1073 if (result == null && !errorIfCant)
1075 addUnique(value, result);
1076 addUnique(valueAlias, result);
1079 protected List _getValueAliases(String valueAlias, List result) {
1080 if (toValueAliases == null)
1082 List a = (List) toValueAliases.get(valueAlias);
1084 addAllUnique(a, result);
1088 protected void _fixValueAliases() {
1089 if (toValueAliases == null)
1090 toValueAliases = new HashMap(1);
1091 for (Iterator it = getAvailableValues().iterator(); it.hasNext();) {
1092 Object value = it.next();
1093 _ensureValueInAliases(value);
1097 protected void _ensureValueInAliases(Object value) {
1098 List result = (List) toValueAliases.get(value);
1100 toValueAliases.put(value, result = new ArrayList(1));
1101 addUnique(value, result);
1104 public BaseProperty swapFirst2ValueAliases() {
1105 for (Iterator it = toValueAliases.keySet().iterator(); it.hasNext();) {
1106 List list = (List) toValueAliases.get(it.next());
1107 if (list.size() < 2)
1109 Object first = list.get(0);
1110 list.set(0, list.get(1));
1120 public UnicodeProperty addName(String string) {
1121 throw new UnsupportedOperationException();
1126 public static abstract class SimpleProperty extends BaseProperty {
1129 public UnicodeProperty addName(String alias) {
1130 propertyAliases.add(alias);
1134 public SimpleProperty setValues(String valueAlias) {
1135 _addToValues(valueAlias, null);
1139 public SimpleProperty setValues(String[] valueAliases,
1140 String[] alternateValueAliases) {
1141 for (int i = 0; i < valueAliases.length; ++i) {
1142 if (valueAliases[i].equals(UNUSED))
1146 alternateValueAliases != null ? alternateValueAliases[i]
1152 public SimpleProperty setValues(List valueAliases) {
1153 this.values = new ArrayList(valueAliases);
1154 for (Iterator it = this.values.iterator(); it.hasNext();) {
1155 _addToValues((String) it.next(), null);
1160 public List _getAvailableValues(List result) {
1163 result.addAll(values);
1167 protected void _fillValues() {
1168 List newvalues = (List) getUnicodeMap_internal()
1169 .getAvailableValues(new ArrayList());
1170 for (Iterator it = newvalues.iterator(); it.hasNext();) {
1171 _addToValues((String) it.next(), null);
1175 private void _addToValues(String item, String alias) {
1177 values = new ArrayList(1);
1178 if (toValueAliases == null)
1180 addUnique(item, values);
1181 _ensureValueInAliases(item);
1182 addValueAlias(item, alias, true);
1184 /* public String _getVersion() {
1190 public static class UnicodeMapProperty extends BaseProperty {
1193 * new UnicodeProperty.UnicodeMapProperty() {
1195 unicodeMap = new UnicodeMap();
1196 unicodeMap.setErrorOnReset(true);
1197 unicodeMap.put(0xD, "CR");
1198 unicodeMap.put(0xA, "LF");
1199 UnicodeProperty cat = getProperty("General_Category");
1200 UnicodeSet temp = cat.getSet("Line_Separator")
1201 .addAll(cat.getSet("Paragraph_Separator"))
1202 .addAll(cat.getSet("Control"))
1203 .addAll(cat.getSet("Format"))
1204 .remove(0xD).remove(0xA).remove(0x200C).remove(0x200D);
1205 unicodeMap.putAll(temp, "Control");
1206 UnicodeSet graphemeExtend = getProperty("Grapheme_Extend").getSet("true");
1207 unicodeMap.putAll(graphemeExtend,"Extend");
1208 UnicodeProperty hangul = getProperty("Hangul_Syllable_Type");
1209 unicodeMap.putAll(hangul.getSet("L"),"L");
1210 unicodeMap.putAll(hangul.getSet("V"),"V");
1211 unicodeMap.putAll(hangul.getSet("T"),"T");
1212 unicodeMap.putAll(hangul.getSet("LV"),"LV");
1213 unicodeMap.putAll(hangul.getSet("LVT"),"LVT");
1214 unicodeMap.setMissing("Other");
1216 }.setMain("Grapheme_Cluster_Break", "GCB", UnicodeProperty.ENUMERATED, version)
1218 protected UnicodeMap unicodeMap;
1220 public UnicodeMapProperty set(UnicodeMap map) {
1225 protected String _getValue(int codepoint) {
1226 return (String) unicodeMap.getValue(codepoint);
1229 /* protected List _getValueAliases(String valueAlias, List result) {
1230 if (!unicodeMap.getAvailableValues().contains(valueAlias)) return result;
1231 result.add(valueAlias);
1232 return result; // no other aliases
1234 */protected List _getAvailableValues(List result) {
1235 return (List) unicodeMap.getAvailableValues(result);