// © 2018 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING // Allow implicit conversion from char16_t* to UnicodeString for this file: // Helpful in toString methods and elsewhere. #define UNISTR_FROM_STRING_EXPLICIT #include "numparse_types.h" #include "numparse_symbols.h" #include "numparse_utils.h" using namespace icu; using namespace icu::numparse; using namespace icu::numparse::impl; SymbolMatcher::SymbolMatcher(const UnicodeString& symbolString, unisets::Key key) { fUniSet = unisets::get(key); if (fUniSet->contains(symbolString)) { fString.setToBogus(); } else { fString = symbolString; } } const UnicodeSet* SymbolMatcher::getSet() const { return fUniSet; } bool SymbolMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode&) const { // Smoke test first; this matcher might be disabled. if (isDisabled(result)) { return false; } // Test the string first in order to consume trailing chars greedily. int overlap = 0; if (!fString.isEmpty()) { overlap = segment.getCommonPrefixLength(fString); if (overlap == fString.length()) { segment.adjustOffset(fString.length()); accept(segment, result); return false; } } int cp = segment.getCodePoint(); if (cp != -1 && fUniSet->contains(cp)) { segment.adjustOffset(U16_LENGTH(cp)); accept(segment, result); return false; } return overlap == segment.length(); } bool SymbolMatcher::smokeTest(const StringSegment& segment) const { return segment.startsWith(*fUniSet) || segment.startsWith(fString); } UnicodeString SymbolMatcher::toString() const { // TODO: Customize output for each symbol return u"<Symbol>"; } IgnorablesMatcher::IgnorablesMatcher(unisets::Key key) : SymbolMatcher({}, key) { } bool IgnorablesMatcher::isFlexible() const { return true; } UnicodeString IgnorablesMatcher::toString() const { return u"<Ignorables>"; } bool IgnorablesMatcher::isDisabled(const ParsedNumber&) const { return false; } void IgnorablesMatcher::accept(StringSegment&, ParsedNumber&) const { // No-op } InfinityMatcher::InfinityMatcher(const DecimalFormatSymbols& dfs) : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol), unisets::INFINITY_KEY) { } bool InfinityMatcher::isDisabled(const ParsedNumber& result) const { return 0 != (result.flags & FLAG_INFINITY); } void InfinityMatcher::accept(StringSegment& segment, ParsedNumber& result) const { result.flags |= FLAG_INFINITY; result.setCharsConsumed(segment); } MinusSignMatcher::MinusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing) : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol), unisets::MINUS_SIGN), fAllowTrailing(allowTrailing) { } bool MinusSignMatcher::isDisabled(const ParsedNumber& result) const { return !fAllowTrailing && result.seenNumber(); } void MinusSignMatcher::accept(StringSegment& segment, ParsedNumber& result) const { result.flags |= FLAG_NEGATIVE; result.setCharsConsumed(segment); } NanMatcher::NanMatcher(const DecimalFormatSymbols& dfs) : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kNaNSymbol), unisets::EMPTY) { } bool NanMatcher::isDisabled(const ParsedNumber& result) const { return result.seenNumber(); } void NanMatcher::accept(StringSegment& segment, ParsedNumber& result) const { result.flags |= FLAG_NAN; result.setCharsConsumed(segment); } PaddingMatcher::PaddingMatcher(const UnicodeString& padString) : SymbolMatcher(padString, unisets::EMPTY) {} bool PaddingMatcher::isFlexible() const { return true; } bool PaddingMatcher::isDisabled(const ParsedNumber&) const { return false; } void PaddingMatcher::accept(StringSegment&, ParsedNumber&) const { // No-op } PercentMatcher::PercentMatcher(const DecimalFormatSymbols& dfs) : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPercentSymbol), unisets::PERCENT_SIGN) { } bool PercentMatcher::isDisabled(const ParsedNumber& result) const { return 0 != (result.flags & FLAG_PERCENT); } void PercentMatcher::accept(StringSegment& segment, ParsedNumber& result) const { result.flags |= FLAG_PERCENT; result.setCharsConsumed(segment); } PermilleMatcher::PermilleMatcher(const DecimalFormatSymbols& dfs) : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPerMillSymbol), unisets::PERMILLE_SIGN) { } bool PermilleMatcher::isDisabled(const ParsedNumber& result) const { return 0 != (result.flags & FLAG_PERMILLE); } void PermilleMatcher::accept(StringSegment& segment, ParsedNumber& result) const { result.flags |= FLAG_PERMILLE; result.setCharsConsumed(segment); } PlusSignMatcher::PlusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing) : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol), unisets::PLUS_SIGN), fAllowTrailing(allowTrailing) { } bool PlusSignMatcher::isDisabled(const ParsedNumber& result) const { return !fAllowTrailing && result.seenNumber(); } void PlusSignMatcher::accept(StringSegment& segment, ParsedNumber& result) const { result.setCharsConsumed(segment); } #endif /* #if !UCONFIG_NO_FORMATTING */