• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.unicode.cldr.unittest;
2 
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.LinkedHashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11 import java.util.TreeMap;
12 import java.util.regex.Matcher;
13 import java.util.regex.Pattern;
14 import java.util.stream.Collectors;
15 import java.util.stream.Stream;
16 
17 import org.unicode.cldr.util.CldrUtility;
18 import org.unicode.cldr.util.Rational;
19 import org.unicode.cldr.util.UnitConverter.ConversionInfo;
20 import org.unicode.cldr.util.UnitConverter.TargetInfo;
21 
22 import com.google.common.base.Joiner;
23 import com.google.common.base.Splitter;
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.ImmutableMap;
26 import com.google.common.collect.ImmutableMultimap;
27 import com.google.common.collect.ImmutableSet;
28 import com.google.common.collect.LinkedHashMultimap;
29 import com.google.common.collect.Multimap;
30 import com.google.common.collect.TreeMultimap;
31 import com.ibm.icu.util.ICUUncheckedIOException;
32 
33 final class NistUnits {
34     final static Multimap<String,String> unitToQuantity;
35     final static Map<String, TargetInfo> derivedUnitToConversion;
36     final static List<ExternalUnitConversionData> externalConversionData;
37     final static Multimap<String, String> idChanges;
38     final static Set<String> skipping;
39 
40     static final Splitter SPLIT_MIDDOT = Splitter.on('·').trimResults();
41     static final Pattern flatExponent = Pattern.compile("([a-zA-Z]+)(-?[0-9]+)?");
42     static final Splitter SPLIT_TABS = Splitter.on('\t').trimResults();
43     static final Splitter SPLIT_COMMAS = Splitter.on(',').trimResults();
44     static final Splitter SPLIT_PARENS = Splitter.on('(').trimResults();
45 
46 
47     static {
48         try {
49             Multimap<String, String> _idChanges = LinkedHashMultimap.create();
50             Set<String> _skipping = new LinkedHashSet<>();
51 
52             List<ExternalUnitConversionData> _externalConversionData = new ArrayList<>();
try(BufferedReader in = CldrUtility.getUTF8Data("external/nistConversions.txt"))53             try (BufferedReader in = CldrUtility.getUTF8Data("external/nistConversions.txt")) {
54                 String quantity = null;
55                 try (Stream<String> s = in.lines()) {
56                     for (String line : (Iterable<String>) s::iterator) {
57                         if (line.startsWith("#")
58                             || line.equals("To convert from\tto\tMultiply by")
59                             || line.startsWith("degree Fahrenheit hour square foot per British thermal unitth inch") // bad NIST data
60                             ) {
61                             continue;
62                         }
63                         List<String> parts = SPLIT_TABS.splitToList(line);
64                         switch(parts.size()) {
65                         case 1:
66                             quantity = parts.get(0);
67                             break;
68                         case 4:
69                             Rational factor = Rational.of((parts.get(2) + parts.get(3)).replace(" ", ""));
70                             ExternalUnitConversionData data = new ExternalUnitConversionData(quantity, parts.get(0), parts.get(1), factor, line, _idChanges);
71                             _externalConversionData.add(data);
72                             break;
73                         default:
74                             _skipping.add(line);
75                         }
76                     }
77                 }
78             }
79 
80             Map<String, TargetInfo> unitToTargetInfo = new TreeMap<>();
81             Map<String,String> _symbolToUnit = new TreeMap<>();
82             Multimap<String,String> _unitToQuantity = TreeMultimap.create();
try(BufferedReader in = CldrUtility.getUTF8Data("external/nistBaseUnits.txt"))83             try (BufferedReader in = CldrUtility.getUTF8Data("external/nistBaseUnits.txt")) {
84                 try (Stream<String> s = in.lines()) {
85                     for (String line : (Iterable<String>) s::iterator) {
86                         if (line.startsWith("#")) {
87                             continue;
88                         }
89                         List<String> parts = SPLIT_TABS.splitToList(line);
90                         //#Base quantity  Name    Symbol
91                         String quantity2 = parts.get(0);
92                         String name = parts.get(1);
93                         String symbol = parts.get(2);
94                         switch(parts.size()) {
95                         case 3:
96                             _symbolToUnit.put(symbol, name);
97                             _unitToQuantity.put(name, quantity2);
98                             break;
99                         }
100                     }
101                 }
102             }
103 
try(BufferedReader in = CldrUtility.getUTF8Data("external/nistDerivedUnits.txt"))104             try (BufferedReader in = CldrUtility.getUTF8Data("external/nistDerivedUnits.txt")) {
105                 try (Stream<String> s = in.lines()) {
106                     for (String line : (Iterable<String>) s::iterator) {
107                         if (line.startsWith("#")) {
108                             continue;
109                         }
110                         List<String> parts = SPLIT_TABS.splitToList(line);
111                         // #Quantity   Special Name    Special symbol  Expression in terms of other SI units   Expression in terms of SI base units
112 
113                         String quantity = parts.get(0);
114                         List<String> quantities = SPLIT_COMMAS.splitToList(quantity).stream()
115                             .map(x ->  SPLIT_PARENS.split(parts.get(0)).iterator().next())
116                             .collect(Collectors.toList());
117                         quantity = Joiner.on(", ").join(quantities);
118 
119                         String name = SPLIT_PARENS.split(parts.get(1)).iterator().next();
120                         if (name.equals("degree Celsius")) {
121                             name = "celsius";
122                         }
123 
124                         String symbol = parts.get(2);
125                         String expressionInOtherSymbols = parts.get(4);
126                         String expressionInBaseSymbols = parts.get(4);
127                         _symbolToUnit.put(symbol, name);
128                         _unitToQuantity.putAll(name, quantities);
129 
130                         final String targetUnit = getUnitFromSymbols(expressionInBaseSymbols, _symbolToUnit);
131                         unitToTargetInfo.put(name, new TargetInfo(targetUnit, new ConversionInfo(Rational.ONE, Rational.ZERO), Collections.emptyMap()));
132 
133                         ExternalUnitConversionData data = new ExternalUnitConversionData(quantity, name, targetUnit, Rational.ONE, line, _idChanges);
134                         _externalConversionData.add(data);
135 
136                     }
137                 }
138             }
139 
140             // Protect everything
141 
142             skipping = ImmutableSet.copyOf(_skipping);
143             idChanges = ImmutableMultimap.copyOf(_idChanges);
144             externalConversionData = ImmutableList.copyOf(_externalConversionData);
145             unitToQuantity = ImmutableMultimap.copyOf(_unitToQuantity);
146             derivedUnitToConversion = ImmutableMap.copyOf(unitToTargetInfo);
147         } catch (IOException e) {
148             throw new ICUUncheckedIOException(e);
149         }
150     }
151 
getUnitFromSymbols(String expressionInBaseSymbols, Map<String, String> symbolToUnit)152     public static String getUnitFromSymbols(String expressionInBaseSymbols, Map<String, String> symbolToUnit) {
153         // handle the irregualar formats
154         if (expressionInBaseSymbols.equals("m/m")) {
155             return "meter-per-meter";
156         } else if (expressionInBaseSymbols.equals("m2/m2")) {
157             return "square-meter-per-square-meter";
158         }
159         // m2 · kg · s-3 · A-1
160         StringBuilder numerator = new StringBuilder();
161         StringBuilder denominator = new StringBuilder();
162         for (String part : SPLIT_MIDDOT.split(expressionInBaseSymbols)) {
163             final Matcher parts = flatExponent.matcher(part);
164             if (!parts.matches()) {
165                 throw new IllegalArgumentException("bad symbol: " + part);
166             }
167             String unit = symbolToUnit.get(parts.group(1));
168             String pow = null;
169             int power = 0;
170             final String exponent = parts.group(2);
171             if (exponent != null) {
172                 power = Integer.parseInt(exponent);
173                 switch(Math.abs(power)) {
174                 case 0: case 1: break;// skip
175                 case 2: pow = "square-"; break;
176                 case 3: pow = "cubic-"; break;
177                 default: pow = "pow" + Math.abs(power) + "-"; break;
178                 }
179             }
180             StringBuilder target = power >= 0 ? numerator : denominator;
181             if (target.length() != 0) {
182                 target.append('-');
183             }
184             if (pow != null) {
185                 target.append(pow);
186             }
187             target.append(unit);
188         }
189         return (numerator.length() == 0 ? "1" : numerator) + (denominator.length() == 0 ? "" : "-per-" + denominator);
190     }
191 
192 }