• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 // © 2017 and later: Unicode, Inc. and others.
3 // License & terms of use: http://www.unicode.org/copyright.html#License
4 package ohos.global.icu.impl.number.parse;
5 
6 import static ohos.global.icu.impl.number.parse.ParsingUtils.safeContains;
7 
8 import ohos.global.icu.impl.StaticUnicodeSets;
9 import ohos.global.icu.impl.StringSegment;
10 import ohos.global.icu.impl.number.DecimalQuantity_DualStorageBCD;
11 import ohos.global.icu.impl.number.Grouper;
12 import ohos.global.icu.text.DecimalFormatSymbols;
13 import ohos.global.icu.text.UnicodeSet;
14 
15 /**
16  * @author sffc
17  * @hide exposed on OHOS
18  *
19  */
20 public class ScientificMatcher implements NumberParseMatcher {
21 
22     private final String exponentSeparatorString;
23     private final DecimalMatcher exponentMatcher;
24     private final IgnorablesMatcher ignorablesMatcher;
25     private final String customMinusSign;
26     private final String customPlusSign;
27 
getInstance(DecimalFormatSymbols symbols, Grouper grouper)28     public static ScientificMatcher getInstance(DecimalFormatSymbols symbols, Grouper grouper) {
29         // TODO: Static-initialize most common instances?
30         return new ScientificMatcher(symbols, grouper);
31     }
32 
ScientificMatcher(DecimalFormatSymbols symbols, Grouper grouper)33     private ScientificMatcher(DecimalFormatSymbols symbols, Grouper grouper) {
34         exponentSeparatorString = symbols.getExponentSeparator();
35         exponentMatcher = DecimalMatcher.getInstance(symbols,
36                 grouper,
37                 ParsingUtils.PARSE_FLAG_INTEGER_ONLY | ParsingUtils.PARSE_FLAG_GROUPING_DISABLED);
38         ignorablesMatcher = IgnorablesMatcher.getInstance(ParsingUtils.PARSE_FLAG_STRICT_IGNORABLES);
39 
40         String minusSign = symbols.getMinusSignString();
41         customMinusSign = safeContains(minusSignSet(), minusSign) ? null : minusSign;
42         String plusSign = symbols.getPlusSignString();
43         customPlusSign = safeContains(plusSignSet(), plusSign) ? null : plusSign;
44     }
45 
minusSignSet()46     private static UnicodeSet minusSignSet() {
47         return StaticUnicodeSets.get(StaticUnicodeSets.Key.MINUS_SIGN);
48     }
49 
plusSignSet()50     private static UnicodeSet plusSignSet() {
51         return StaticUnicodeSets.get(StaticUnicodeSets.Key.PLUS_SIGN);
52     }
53 
54     @Override
match(StringSegment segment, ParsedNumber result)55     public boolean match(StringSegment segment, ParsedNumber result) {
56         // Only accept scientific notation after the mantissa.
57         if (!result.seenNumber()) {
58             return false;
59         }
60 
61         // Only accept one exponent per string.
62         if (0 != (result.flags & ParsedNumber.FLAG_HAS_EXPONENT)) {
63             return false;
64         }
65 
66         // First match the scientific separator, and then match another number after it.
67         // NOTE: This is guarded by the smoke test; no need to check exponentSeparatorString length again.
68         int initialOffset = segment.getOffset();
69         int overlap = segment.getCommonPrefixLength(exponentSeparatorString);
70         if (overlap == exponentSeparatorString.length()) {
71             // Full exponent separator match.
72 
73             // First attempt to get a code point, returning true if we can't get one.
74             if (segment.length() == overlap) {
75                 return true;
76             }
77             segment.adjustOffset(overlap);
78 
79             // Allow ignorables before the sign.
80             // Note: call site is guarded by the segment.length() check above.
81             ignorablesMatcher.match(segment, null);
82             if (segment.length() == 0) {
83                 segment.setOffset(initialOffset);
84                 return true;
85             }
86 
87             // Allow a sign, and then try to match digits.
88             int exponentSign = 1;
89             if (segment.startsWith(minusSignSet())) {
90                 exponentSign = -1;
91                 segment.adjustOffsetByCodePoint();
92             } else if (segment.startsWith(plusSignSet())) {
93                 segment.adjustOffsetByCodePoint();
94             } else if (segment.startsWith(customMinusSign)) {
95                 overlap = segment.getCommonPrefixLength(customMinusSign);
96                 if (overlap != customMinusSign.length()) {
97                     // Partial custom sign match
98                     segment.setOffset(initialOffset);
99                     return true;
100                 }
101                 exponentSign = -1;
102                 segment.adjustOffset(overlap);
103             } else if (segment.startsWith(customPlusSign)) {
104                 overlap = segment.getCommonPrefixLength(customPlusSign);
105                 if (overlap != customPlusSign.length()) {
106                     // Partial custom sign match
107                     segment.setOffset(initialOffset);
108                     return true;
109                 }
110                 segment.adjustOffset(overlap);
111             }
112 
113             // Return true if the segment is empty.
114             if (segment.length() == 0) {
115                 segment.setOffset(initialOffset);
116                 return true;
117             }
118 
119             // Allow ignorables after the sign.
120             // Note: call site is guarded by the segment.length() check above.
121             ignorablesMatcher.match(segment, null);
122             if (segment.length() == 0) {
123                 segment.setOffset(initialOffset);
124                 return true;
125             }
126 
127             // We are supposed to accept E0 after NaN, so we need to make sure result.quantity is available.
128             boolean wasNull = (result.quantity == null);
129             if (wasNull) {
130                 result.quantity = new DecimalQuantity_DualStorageBCD();
131             }
132             int digitsOffset = segment.getOffset();
133             boolean digitsReturnValue = exponentMatcher.match(segment, result, exponentSign);
134             if (wasNull) {
135                 result.quantity = null;
136             }
137 
138             if (segment.getOffset() != digitsOffset) {
139                 // At least one exponent digit was matched.
140                 result.flags |= ParsedNumber.FLAG_HAS_EXPONENT;
141             } else {
142                 // No exponent digits were matched
143                 segment.setOffset(initialOffset);
144             }
145             return digitsReturnValue;
146 
147         } else if (overlap == segment.length()) {
148             // Partial exponent separator match
149             return true;
150         }
151 
152         // No match
153         return false;
154     }
155 
156     @Override
smokeTest(StringSegment segment)157     public boolean smokeTest(StringSegment segment) {
158         return segment.startsWith(exponentSeparatorString);
159     }
160 
161     @Override
postProcess(ParsedNumber result)162     public void postProcess(ParsedNumber result) {
163         // No-op
164     }
165 
166     @Override
toString()167     public String toString() {
168         return "<ScientificMatcher " + exponentSeparatorString + ">";
169     }
170 }
171