diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/ValidIdentifiers.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/ValidIdentifiers.java new file mode 100644 index 00000000000..deb75dd1b34 --- /dev/null +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/ValidIdentifiers.java @@ -0,0 +1,231 @@ +/* + ******************************************************************************* + * Copyright (C) 2015, International Business Machines Corporation and + * others. All Rights Reserved. + ******************************************************************************* + */ +package com.ibm.icu.impl; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.ibm.icu.util.UResourceBundle; +import com.ibm.icu.util.UResourceBundleIterator; + +/** + * @author markdavis + * + */ +public class ValidIdentifiers { + + public enum Datatype { + currency, + language, + region, + script, + subdivision, + unit, + variant, + } + + public enum Datasubtype { + deprecated, + private_use, + regular, + special, + unknown, + macroregion, + } + + static class ValiditySet { + public final Set regularData; + public final Map> subdivisionData; + public ValiditySet(Set plainData, boolean makeMap) { + if (makeMap) { + HashMap> _subdivisionData = new HashMap>(); + for (String s : plainData) { + int pos = s.indexOf('-'); + String key = s.substring(0,pos); + Set oldSet = _subdivisionData.get(key); + if (oldSet == null) { + _subdivisionData.put(key, oldSet = new HashSet()); + } + oldSet.add(s.substring(pos+1)); + } + this.regularData = null; + HashMap> _subdivisionData2 = new HashMap>(); + // protect the sets + for (Entry> e : _subdivisionData.entrySet()) { + Set value = e.getValue(); + // optimize a bit by using singleton + Set set = value.size() == 1 ? Collections.singleton(value.iterator().next()) + : Collections.unmodifiableSet(value); + _subdivisionData2.put(e.getKey(), set); + } + + this.subdivisionData = Collections.unmodifiableMap(_subdivisionData2); + } else { + this.regularData = Collections.unmodifiableSet(plainData); + this.subdivisionData = null; + } + } + /** + * @param code + * @return + */ + public boolean contains(String code) { + if (regularData != null) { + return regularData.contains(code); + } else { + int pos = code.indexOf('-'); + String key = code.substring(0,pos); + final String value = code.substring(pos+1); + return contains(key, value); + } + } + + public boolean contains(String key, String value) { + Set oldSet = subdivisionData.get(key); + return oldSet != null && oldSet.contains(value); + } + + @Override + public String toString() { + if (regularData != null) { + return regularData.toString(); + } else { + return subdivisionData.toString(); + } + } + } + + static class ValidityData { + static final Map> data; + static { + Map> _data = new EnumMap>(Datatype.class); + UResourceBundle suppData = UResourceBundle.getBundleInstance( + ICUResourceBundle.ICU_BASE_NAME, + "supplementalData", + ICUResourceBundle.ICU_DATA_CLASS_LOADER); + UResourceBundle validityInfo = suppData.get("idValidity"); + for(UResourceBundleIterator datatypeIterator = validityInfo.getIterator(); + datatypeIterator.hasNext();) { + UResourceBundle datatype = datatypeIterator.next(); + String rawKey = datatype.getKey(); + Datatype key = Datatype.valueOf(rawKey); + Map values = new EnumMap(Datasubtype.class); + for(UResourceBundleIterator datasubtypeIterator = datatype.getIterator(); + datasubtypeIterator.hasNext();) { + UResourceBundle datasubtype = datasubtypeIterator.next(); + String rawsubkey = datasubtype.getKey(); + Datasubtype subkey = Datasubtype.valueOf(rawsubkey); + // handle single value specially + Set subvalues = new HashSet(); + if (datasubtype.getType() == UResourceBundle.STRING) { + addRange(datasubtype.getString(), subvalues); + } else { + for (String string : datasubtype.getStringArray()) { + addRange(string, subvalues); + } + } + values.put(subkey, new ValiditySet(subvalues, key == Datatype.subdivision)); + } + _data.put(key, Collections.unmodifiableMap(values)); + } + data = Collections.unmodifiableMap(_data); + } + private static void addRange(String string, Set subvalues) { + int pos = string.indexOf('~'); + if (pos < 0) { + subvalues.add(string); + } else { + StringRange.expand(string.substring(0,pos), string.substring(pos+1), false, subvalues); + } + } + static Map> getData() { + return data; + } + + /** + * Returns the Datasubtype containing the code, or null if there is none. + * @param datatype + * @param datasubtypes + * @param code + * @return + */ + static Datasubtype isValid(Datatype datatype, Set datasubtypes, String code) { + Map subtable = data.get(datatype); + if (subtable != null) { + for (Datasubtype datasubtype : datasubtypes) { + ValiditySet validitySet = subtable.get(datasubtype); + if (validitySet != null) { + if (validitySet.contains(code)) { + return datasubtype; + } + } + } + } + return null; + } + + static Datasubtype isValid(Datatype datatype, Set datasubtypes, String code, String value) { + Map subtable = data.get(datatype); + if (subtable != null) { + for (Datasubtype datasubtype : datasubtypes) { + ValiditySet validitySet = subtable.get(datasubtype); + if (validitySet != null) { + if (validitySet.contains(code, value)) { + return datasubtype; + } + } + } + } + return null; + } + + } + + // Quick testing for now + + public static void main(String[] args) { + showValid(Datatype.script, EnumSet.of(Datasubtype.regular, Datasubtype.unknown), "Zzzz"); + showValid(Datatype.script, EnumSet.of(Datasubtype.regular), "Zzzz"); + showValid(Datatype.subdivision, EnumSet.of(Datasubtype.regular), "US-CA"); + showValid(Datatype.subdivision, EnumSet.of(Datasubtype.regular), "US", "CA"); + showValid(Datatype.subdivision, EnumSet.of(Datasubtype.regular), "US-?"); + showValid(Datatype.subdivision, EnumSet.of(Datasubtype.regular), "US", "?"); + showAll(); + } + + private static void showAll() { + Map> data = ValidityData.getData(); + for (Entry> e1 : data.entrySet()) { + System.out.println(e1.getKey()); + for (Entry e2 : e1.getValue().entrySet()) { + System.out.println("\t" + e2.getKey()); + System.out.println("\t\t" + e2.getValue()); + } + } + } + + /** + * @param script + * @param of + * @param string + */ + private static void showValid(Datatype datatype, Set datasubtypes, String code) { + Datasubtype value = ValidityData.isValid(datatype, datasubtypes, code); + System.out.println(datatype + ", " + datasubtypes + ", " + code + " => " + value); + } + private static void showValid(Datatype datatype, Set datasubtypes, String code, String value2) { + Datasubtype value = ValidityData.isValid(datatype, datasubtypes, code, value2); + System.out.println(datatype + ", " + datasubtypes + ", " + code + ", " + value + " => " + value); + } + +}