xref: /aosp_15_r20/external/cldr/tools/cldr-code/src/main/java/org/unicode/cldr/util/Units.java (revision 912701f9769bb47905792267661f0baf2b85bed5)
1 package org.unicode.cldr.util;
2 
3 import com.google.common.collect.BiMap;
4 import com.google.common.collect.ImmutableBiMap;
5 import com.google.common.collect.ImmutableMap;
6 import com.google.common.collect.ImmutableMultimap;
7 import com.google.common.collect.Multimap;
8 import com.google.common.collect.TreeMultimap;
9 import com.ibm.icu.text.MessageFormat;
10 import com.ibm.icu.text.UnicodeSet;
11 import com.ibm.icu.text.UnicodeSetSpanner;
12 import java.util.Collection;
13 import java.util.Locale;
14 import java.util.Map;
15 import java.util.Set;
16 import java.util.TreeMap;
17 import java.util.regex.Pattern;
18 import org.unicode.cldr.test.ExampleGenerator;
19 import org.unicode.cldr.util.StandardCodes.LstrType;
20 import org.unicode.cldr.util.Validity.Status;
21 
22 public class Units {
23 
24     private static final UnicodeSet WHITESPACE = new UnicodeSet("[:whitespace:]").freeze();
25     public static Pattern NO_SPACE_PREFIX =
26             Pattern.compile(
27                     "\\}"
28                             + ExampleGenerator.backgroundEndSymbol
29                             + "?\\p{L}|\\p{L}"
30                             + ExampleGenerator.backgroundStartSymbol
31                             + "?\\{");
32 
combinePattern( String unitFormat, String compoundPattern, boolean lowercaseUnitIfNoSpaceInCompound)33     public static String combinePattern(
34             String unitFormat, String compoundPattern, boolean lowercaseUnitIfNoSpaceInCompound) {
35         // meterFormat of the form {0} meters or {0} Meter
36         // compoundPattern is of the form Z{0} or Zetta{0}
37 
38         // extract the unit
39         String modUnit = (String) SPACE_SPANNER.trim(unitFormat.replace("{0}", ""));
40         Object[] parameters = {modUnit};
41 
42         String modFormat =
43                 unitFormat.replace(modUnit, MessageFormat.format(compoundPattern, parameters));
44         if (modFormat.equals(unitFormat)) {
45             // didn't work, so fall back
46             Object[] parameters1 = {unitFormat};
47             modFormat = MessageFormat.format(compoundPattern, parameters1);
48         }
49 
50         // hack to fix casing
51         if (lowercaseUnitIfNoSpaceInCompound && NO_SPACE_PREFIX.matcher(compoundPattern).find()) {
52             modFormat = modFormat.replace(modUnit, modUnit.toLowerCase(Locale.ENGLISH));
53         }
54 
55         return modFormat;
56     }
57 
58     static final UnicodeSetSpanner SPACE_SPANNER = new UnicodeSetSpanner(WHITESPACE);
59 
60     public static final Map<String, String> CORE_TO_TYPE;
61     public static final Multimap<String, String> TYPE_TO_CORE;
62     public static final BiMap<String, String> LONG_TO_SHORT;
63 
64     static {
65         Set<String> VALID_UNITS =
66                 Validity.getInstance().getStatusToCodes(LstrType.unit).get(Status.regular);
67 
68         Map<String, String> coreToType = new TreeMap<>();
69         Multimap<String, String> typeToCore = TreeMultimap.create();
70         Map<String, String> longToShort = new TreeMap<>();
71         for (String s : VALID_UNITS) {
72             int dashPos = s.indexOf('-');
73             String unitType = s.substring(0, dashPos);
74             String coreUnit = s.substring(dashPos + 1);
longToShort.put(s, coreUnit)75             longToShort.put(s, coreUnit);
76             // coreUnit = converter.fixDenormalized(coreUnit);
coreToType.put(coreUnit, unitType)77             coreToType.put(coreUnit, unitType);
typeToCore.put(unitType, coreUnit)78             typeToCore.put(unitType, coreUnit);
79         }
80         CORE_TO_TYPE = ImmutableMap.copyOf(coreToType);
81         TYPE_TO_CORE = ImmutableMultimap.copyOf(typeToCore);
82         LONG_TO_SHORT = ImmutableBiMap.copyOf(longToShort);
83     }
84 
85     public static class TypeAndCore {
86         public String type;
87         public String core;
88     }
89     /**
90      * Returns the type and core for a unit, be it long or short
91      *
92      * @param longOrShortUnit
93      * @param core
94      * @return
95      * @return
96      */
splitUnit(String longOrShortUnit, TypeAndCore typeAndCore)97     public static TypeAndCore splitUnit(String longOrShortUnit, TypeAndCore typeAndCore) {
98         int dashPos = longOrShortUnit.indexOf('-');
99         String unitType = longOrShortUnit.substring(0, dashPos);
100         Collection<String> cores = TYPE_TO_CORE.get(unitType);
101         if (cores.isEmpty()) { // short unit
102             typeAndCore.type = CORE_TO_TYPE.get(longOrShortUnit);
103             typeAndCore.core = longOrShortUnit;
104         } else {
105             typeAndCore.type = unitType;
106             typeAndCore.core = longOrShortUnit.substring(dashPos + 1);
107         }
108         return typeAndCore;
109     }
110 
getShort(String longUnit)111     public static String getShort(String longUnit) {
112         String result = LONG_TO_SHORT.get(longUnit);
113         return result == null ? longUnit : result;
114     }
115 
getLong(String shortId)116     public static String getLong(String shortId) {
117         String result = LONG_TO_SHORT.inverse().get(shortId);
118         return result == null ? shortId : result;
119     }
120 }
121