1 package org.unicode.cldr.util; 2 3 import java.util.Iterator; 4 5 import org.unicode.cldr.util.SupplementalDataInfo.UnitIdComponentType; 6 7 import com.google.common.base.Joiner; 8 import com.google.common.base.Splitter; 9 import com.ibm.icu.util.Output; 10 11 public class UnitParser { 12 private static final CLDRConfig CLDR_CONFIG = CLDRConfig.getInstance(); 13 private static final CLDRConfig info = CLDR_CONFIG; 14 private static final SupplementalDataInfo SDI = info.getSupplementalDataInfo(); 15 public static final Splitter DASH_SPLITTER = Splitter.on('-'); 16 public static final Joiner DASH_JOIN = Joiner.on('-'); 17 18 private String bufferedItem = null; 19 private UnitIdComponentType bufferedType = null; 20 private Iterator<String> source; 21 set(Iterator<String> source)22 public UnitParser set(Iterator<String> source) { 23 bufferedItem = null; 24 this.source = source; 25 return this; 26 } 27 set(Iterable<String> source)28 public UnitParser set(Iterable<String> source) { 29 return set(source.iterator()); 30 } 31 set(String source)32 public UnitParser set(String source) { 33 return set(UnitParser.DASH_SPLITTER.split(source).iterator()); 34 } 35 36 private enum State {start, havePrefix, haveBaseOrSuffix} 37 38 /** 39 * Parses the next segment in the source from set. 40 * @param output returns type type of the item, where base is for prefix* base suffix* 41 * @return a unit segment of the form: prefix* base suffix*, and, per, or power 42 */ nextParse(Output<UnitIdComponentType> type)43 public String nextParse(Output<UnitIdComponentType> type) { 44 String output = null; 45 State state = State.start; 46 UnitIdComponentType outputType = null; 47 48 while (true) { 49 if (bufferedItem == null) { 50 if (!source.hasNext()) { 51 break; 52 } 53 bufferedItem = source.next(); 54 bufferedType = SDI.getUnitIdComponentType(bufferedItem); 55 } 56 switch(bufferedType) { 57 case prefix: 58 switch(state) { 59 case start: 60 state = State.havePrefix; 61 break; 62 case havePrefix: // ok, continue 63 break; 64 case haveBaseOrSuffix: 65 type.value = outputType == UnitIdComponentType.suffix ? UnitIdComponentType.base : outputType; 66 return output; 67 } 68 break; 69 case base: 70 switch(state) { 71 case start: 72 case havePrefix: 73 state = State.haveBaseOrSuffix; 74 break; 75 case haveBaseOrSuffix: // have stuff to return 76 type.value = outputType == UnitIdComponentType.suffix ? UnitIdComponentType.base : outputType; 77 return output; 78 } 79 break; 80 case suffix: 81 switch(state) { 82 case start: 83 case havePrefix: 84 throw new IllegalArgumentException("Unit suffix must follow base: " + output + " ❌ " + bufferedItem); 85 case haveBaseOrSuffix: // ok, continue 86 break; 87 } 88 break; 89 case and: 90 case per: 91 case power: 92 switch(state) { 93 case start: // return this item 94 output = bufferedItem; 95 bufferedItem = null; 96 type.value = outputType; 97 return output; 98 case havePrefix: 99 throw new IllegalArgumentException("Unit prefix must be followed with base: " + output + " ❌ " + bufferedItem); 100 case haveBaseOrSuffix: // have stuff to return 101 type.value = outputType == UnitIdComponentType.suffix ? UnitIdComponentType.base : outputType; 102 return output; 103 } 104 break; 105 } 106 output = output == null ? bufferedItem : output + "-" + bufferedItem; 107 bufferedItem = null; 108 outputType = bufferedType; 109 } 110 switch(state) { 111 default: 112 case start: 113 return null; 114 case havePrefix: 115 throw new IllegalArgumentException("Unit prefix must be followed with base: " + output + " ❌ " + bufferedItem); 116 case haveBaseOrSuffix: // have stuff to return 117 type.value = outputType == UnitIdComponentType.suffix ? UnitIdComponentType.base : outputType; 118 return output; 119 } 120 } 121 122 // TODO create from custom map getUnitIdComponentType(String part)123 public UnitIdComponentType getUnitIdComponentType(String part) { 124 return SDI.getUnitIdComponentType(part); 125 } 126 } 127