• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #include "unicode/utypes.h"
5 
6 #if !UCONFIG_NO_FORMATTING
7 
8 // Allow implicit conversion from char16_t* to UnicodeString for this file:
9 // Helpful in toString methods and elsewhere.
10 #define UNISTR_FROM_STRING_EXPLICIT
11 
12 #include "numparse_types.h"
13 #include "numparse_symbols.h"
14 #include "numparse_utils.h"
15 
16 using namespace icu;
17 using namespace icu::numparse;
18 using namespace icu::numparse::impl;
19 
20 
SymbolMatcher(const UnicodeString & symbolString,unisets::Key key)21 SymbolMatcher::SymbolMatcher(const UnicodeString& symbolString, unisets::Key key) {
22     fUniSet = unisets::get(key);
23     if (fUniSet->contains(symbolString)) {
24         fString.setToBogus();
25     } else {
26         fString = symbolString;
27     }
28 }
29 
getSet() const30 const UnicodeSet* SymbolMatcher::getSet() const {
31     return fUniSet;
32 }
33 
match(StringSegment & segment,ParsedNumber & result,UErrorCode &) const34 bool SymbolMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode&) const {
35     // Smoke test first; this matcher might be disabled.
36     if (isDisabled(result)) {
37         return false;
38     }
39 
40     // Test the string first in order to consume trailing chars greedily.
41     int overlap = 0;
42     if (!fString.isEmpty()) {
43         overlap = segment.getCommonPrefixLength(fString);
44         if (overlap == fString.length()) {
45             segment.adjustOffset(fString.length());
46             accept(segment, result);
47             return false;
48         }
49     }
50 
51     int cp = segment.getCodePoint();
52     if (cp != -1 && fUniSet->contains(cp)) {
53         segment.adjustOffset(U16_LENGTH(cp));
54         accept(segment, result);
55         return false;
56     }
57 
58     return overlap == segment.length();
59 }
60 
smokeTest(const StringSegment & segment) const61 bool SymbolMatcher::smokeTest(const StringSegment& segment) const {
62     return segment.startsWith(*fUniSet) || segment.startsWith(fString);
63 }
64 
toString() const65 UnicodeString SymbolMatcher::toString() const {
66     // TODO: Customize output for each symbol
67     return u"<Symbol>";
68 }
69 
70 
IgnorablesMatcher(unisets::Key key)71 IgnorablesMatcher::IgnorablesMatcher(unisets::Key key)
72         : SymbolMatcher({}, key) {
73 }
74 
isFlexible() const75 bool IgnorablesMatcher::isFlexible() const {
76     return true;
77 }
78 
toString() const79 UnicodeString IgnorablesMatcher::toString() const {
80     return u"<Ignorables>";
81 }
82 
isDisabled(const ParsedNumber &) const83 bool IgnorablesMatcher::isDisabled(const ParsedNumber&) const {
84     return false;
85 }
86 
accept(StringSegment &,ParsedNumber &) const87 void IgnorablesMatcher::accept(StringSegment&, ParsedNumber&) const {
88     // No-op
89 }
90 
91 
InfinityMatcher(const DecimalFormatSymbols & dfs)92 InfinityMatcher::InfinityMatcher(const DecimalFormatSymbols& dfs)
93         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol), unisets::INFINITY_KEY) {
94 }
95 
isDisabled(const ParsedNumber & result) const96 bool InfinityMatcher::isDisabled(const ParsedNumber& result) const {
97     return 0 != (result.flags & FLAG_INFINITY);
98 }
99 
accept(StringSegment & segment,ParsedNumber & result) const100 void InfinityMatcher::accept(StringSegment& segment, ParsedNumber& result) const {
101     result.flags |= FLAG_INFINITY;
102     result.setCharsConsumed(segment);
103 }
104 
105 
MinusSignMatcher(const DecimalFormatSymbols & dfs,bool allowTrailing)106 MinusSignMatcher::MinusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing)
107         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol), unisets::MINUS_SIGN),
108           fAllowTrailing(allowTrailing) {
109 }
110 
isDisabled(const ParsedNumber & result) const111 bool MinusSignMatcher::isDisabled(const ParsedNumber& result) const {
112     return !fAllowTrailing && result.seenNumber();
113 }
114 
accept(StringSegment & segment,ParsedNumber & result) const115 void MinusSignMatcher::accept(StringSegment& segment, ParsedNumber& result) const {
116     result.flags |= FLAG_NEGATIVE;
117     result.setCharsConsumed(segment);
118 }
119 
120 
NanMatcher(const DecimalFormatSymbols & dfs)121 NanMatcher::NanMatcher(const DecimalFormatSymbols& dfs)
122         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kNaNSymbol), unisets::EMPTY) {
123 }
124 
isDisabled(const ParsedNumber & result) const125 bool NanMatcher::isDisabled(const ParsedNumber& result) const {
126     return result.seenNumber();
127 }
128 
accept(StringSegment & segment,ParsedNumber & result) const129 void NanMatcher::accept(StringSegment& segment, ParsedNumber& result) const {
130     result.flags |= FLAG_NAN;
131     result.setCharsConsumed(segment);
132 }
133 
134 
PaddingMatcher(const UnicodeString & padString)135 PaddingMatcher::PaddingMatcher(const UnicodeString& padString)
136         : SymbolMatcher(padString, unisets::EMPTY) {}
137 
isFlexible() const138 bool PaddingMatcher::isFlexible() const {
139     return true;
140 }
141 
isDisabled(const ParsedNumber &) const142 bool PaddingMatcher::isDisabled(const ParsedNumber&) const {
143     return false;
144 }
145 
accept(StringSegment &,ParsedNumber &) const146 void PaddingMatcher::accept(StringSegment&, ParsedNumber&) const {
147     // No-op
148 }
149 
150 
PercentMatcher(const DecimalFormatSymbols & dfs)151 PercentMatcher::PercentMatcher(const DecimalFormatSymbols& dfs)
152         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPercentSymbol), unisets::PERCENT_SIGN) {
153 }
154 
isDisabled(const ParsedNumber & result) const155 bool PercentMatcher::isDisabled(const ParsedNumber& result) const {
156     return 0 != (result.flags & FLAG_PERCENT);
157 }
158 
accept(StringSegment & segment,ParsedNumber & result) const159 void PercentMatcher::accept(StringSegment& segment, ParsedNumber& result) const {
160     result.flags |= FLAG_PERCENT;
161     result.setCharsConsumed(segment);
162 }
163 
164 
PermilleMatcher(const DecimalFormatSymbols & dfs)165 PermilleMatcher::PermilleMatcher(const DecimalFormatSymbols& dfs)
166         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPerMillSymbol), unisets::PERMILLE_SIGN) {
167 }
168 
isDisabled(const ParsedNumber & result) const169 bool PermilleMatcher::isDisabled(const ParsedNumber& result) const {
170     return 0 != (result.flags & FLAG_PERMILLE);
171 }
172 
accept(StringSegment & segment,ParsedNumber & result) const173 void PermilleMatcher::accept(StringSegment& segment, ParsedNumber& result) const {
174     result.flags |= FLAG_PERMILLE;
175     result.setCharsConsumed(segment);
176 }
177 
178 
PlusSignMatcher(const DecimalFormatSymbols & dfs,bool allowTrailing)179 PlusSignMatcher::PlusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing)
180         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol), unisets::PLUS_SIGN),
181           fAllowTrailing(allowTrailing) {
182 }
183 
isDisabled(const ParsedNumber & result) const184 bool PlusSignMatcher::isDisabled(const ParsedNumber& result) const {
185     return !fAllowTrailing && result.seenNumber();
186 }
187 
accept(StringSegment & segment,ParsedNumber & result) const188 void PlusSignMatcher::accept(StringSegment& segment, ParsedNumber& result) const {
189     result.setCharsConsumed(segment);
190 }
191 
192 
193 #endif /* #if !UCONFIG_NO_FORMATTING */
194