001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (http://h2database.com/html/license.html).
004: * Initial Developer: H2 Group
005: */
006: package org.h2.value;
007:
008: import java.text.CollationKey;
009: import java.text.Collator;
010: import java.util.Locale;
011:
012: import org.h2.util.SmallLRUCache;
013: import org.h2.util.StringUtils;
014:
015: /**
016: * Instances of this class can compare strings.
017: * Case sensitive and case insensitive comparison is supported,
018: * and comparison using a collator.
019: */
020: public class CompareMode {
021:
022: /**
023: * This constant means there is no collator set,
024: * and the default string comparison is to be used.
025: */
026: public static final String OFF = "OFF";
027:
028: private final Collator collator;
029: private final String name;
030: private final SmallLRUCache collationKeys;
031:
032: /**
033: * Create a new compare mode with the given collator and cache size.
034: * The cache is used to speed up comparison when using a collator;
035: * CollationKey objects are cached.
036: *
037: * @param collator the collator or null
038: * @param name the collation name or null
039: * @param cacheSize the number of entries in the CollationKey cache
040: */
041: public CompareMode(Collator collator, String name, int cacheSize) {
042: this .collator = collator;
043: if (collator != null && cacheSize != 0) {
044: collationKeys = new SmallLRUCache(cacheSize);
045: } else {
046: collationKeys = null;
047: }
048: this .name = name == null ? OFF : name;
049: }
050:
051: /**
052: * Compare two characters in a string.
053: *
054: * @param a the first string
055: * @param ai the character index in the first string
056: * @param b the second string
057: * @param bi the character index in the second string
058: * @param ignoreCase true if a case-insensitive comparison should be made
059: * @return true if the characters are equals
060: */
061: public boolean equalsChars(String a, int ai, String b, int bi,
062: boolean ignoreCase) {
063: if (collator != null) {
064: return compareString(a.substring(ai, ai + 1), b.substring(
065: bi, bi + 1), ignoreCase) == 0;
066: }
067: char ca = a.charAt(ai);
068: char cb = b.charAt(bi);
069: if (ignoreCase) {
070: ca = Character.toUpperCase(ca);
071: cb = Character.toUpperCase(cb);
072: }
073: return ca == cb;
074: }
075:
076: /**
077: * Compare two strings.
078: *
079: * @param a the first string
080: * @param b the second string
081: * @param ignoreCase true if a case-insensitive comparison should be made
082: * @return -1 if the first string is 'smaller', 1 if the second string is
083: * smaller, and 0 if they are equal
084: */
085: public int compareString(String a, String b, boolean ignoreCase) {
086: if (collator == null) {
087: if (ignoreCase) {
088: return a.compareToIgnoreCase(b);
089: }
090: return a.compareTo(b);
091: }
092: if (ignoreCase) {
093: // this is locale sensitive
094: a = a.toUpperCase();
095: b = b.toUpperCase();
096: }
097: int comp;
098: if (collationKeys != null) {
099: CollationKey aKey = getKey(a);
100: CollationKey bKey = getKey(b);
101: comp = aKey.compareTo(bKey);
102: } else {
103: comp = collator.compare(a, b);
104: }
105: return comp;
106: }
107:
108: private CollationKey getKey(String a) {
109: synchronized (collationKeys) {
110: CollationKey key = (CollationKey) collationKeys.get(a);
111: if (key == null) {
112: key = collator.getCollationKey(a);
113: collationKeys.put(a, key);
114: }
115: return key;
116: }
117: }
118:
119: /**
120: * Get the collation name.
121: *
122: * @param l the locale
123: * @return the name of the collation
124: */
125: public static String getName(Locale l) {
126: Locale english = Locale.ENGLISH;
127: String name = l.getDisplayLanguage(english) + ' '
128: + l.getDisplayCountry(english) + ' ' + l.getVariant();
129: name = StringUtils
130: .toUpperEnglish(name.trim().replace(' ', '_'));
131: return name;
132: }
133:
134: private static boolean compareLocaleNames(Locale locale, String name) {
135: return name.equalsIgnoreCase(locale.toString())
136: || name.equalsIgnoreCase(getName(locale));
137: }
138:
139: public static Collator getCollator(String name) {
140: Collator result = null;
141: if (name.length() == 2) {
142: Locale locale = new Locale(name.toLowerCase(), "");
143: if (compareLocaleNames(locale, name)) {
144: result = Collator.getInstance(locale);
145: }
146: } else if (name.length() == 5) {
147: int idx = name.indexOf('_');
148: if (idx >= 0) {
149: String language = name.substring(0, idx).toLowerCase();
150: String country = name.substring(idx + 1);
151: Locale locale = new Locale(language, country);
152: if (compareLocaleNames(locale, name)) {
153: result = Collator.getInstance(locale);
154: }
155: }
156: }
157: if (result == null) {
158: Locale[] locales = Collator.getAvailableLocales();
159: for (int i = 0; i < locales.length; i++) {
160: Locale locale = locales[i];
161: if (compareLocaleNames(locale, name)) {
162: result = Collator.getInstance(locale);
163: break;
164: }
165: }
166: }
167: return result;
168: }
169:
170: public String getName() {
171: return name;
172: }
173:
174: }
|