2018-02-10 06:36:07 +00:00
|
|
|
// © 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 && !UPRV_INCOMPLETE_CPP11_SUPPORT
|
|
|
|
|
|
|
|
#include "numparse_types.h"
|
|
|
|
#include "numparse_affixes.h"
|
2018-02-10 10:01:46 +00:00
|
|
|
#include "numparse_utils.h"
|
|
|
|
#include "number_utils.h"
|
2018-02-10 06:36:07 +00:00
|
|
|
|
|
|
|
using namespace icu;
|
|
|
|
using namespace icu::numparse;
|
|
|
|
using namespace icu::numparse::impl;
|
2018-02-10 10:01:46 +00:00
|
|
|
using namespace icu::number;
|
|
|
|
using namespace icu::number::impl;
|
2018-02-10 06:36:07 +00:00
|
|
|
|
|
|
|
|
2018-02-10 10:01:46 +00:00
|
|
|
AffixPatternMatcherBuilder::AffixPatternMatcherBuilder(const UnicodeString& pattern,
|
2018-02-10 10:57:30 +00:00
|
|
|
AffixTokenMatcherWarehouse& warehouse,
|
2018-02-10 10:01:46 +00:00
|
|
|
IgnorablesMatcher* ignorables)
|
|
|
|
: fMatchersLen(0),
|
|
|
|
fLastTypeOrCp(0),
|
|
|
|
fPattern(pattern),
|
2018-02-10 10:57:30 +00:00
|
|
|
fWarehouse(warehouse),
|
2018-02-10 10:01:46 +00:00
|
|
|
fIgnorables(ignorables) {}
|
2018-02-10 06:36:07 +00:00
|
|
|
|
2018-02-10 10:01:46 +00:00
|
|
|
void AffixPatternMatcherBuilder::consumeToken(AffixPatternType type, UChar32 cp, UErrorCode& status) {
|
|
|
|
// This is called by AffixUtils.iterateWithConsumer() for each token.
|
2018-02-10 06:36:07 +00:00
|
|
|
|
2018-02-10 10:01:46 +00:00
|
|
|
// Add an ignorables matcher between tokens except between two literals, and don't put two
|
|
|
|
// ignorables matchers in a row.
|
|
|
|
if (fIgnorables != nullptr && fMatchersLen > 0 &&
|
|
|
|
(fLastTypeOrCp < 0 || !fIgnorables->getSet()->contains(fLastTypeOrCp))) {
|
|
|
|
addMatcher(*fIgnorables);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type != TYPE_CODEPOINT) {
|
|
|
|
// Case 1: the token is a symbol.
|
|
|
|
switch (type) {
|
|
|
|
case TYPE_MINUS_SIGN:
|
2018-02-10 11:32:18 +00:00
|
|
|
addMatcher(fWarehouse.minusSign());
|
2018-02-10 10:01:46 +00:00
|
|
|
break;
|
|
|
|
case TYPE_PLUS_SIGN:
|
2018-02-10 11:32:18 +00:00
|
|
|
addMatcher(fWarehouse.plusSign());
|
2018-02-10 10:01:46 +00:00
|
|
|
break;
|
|
|
|
case TYPE_PERCENT:
|
2018-02-10 11:32:18 +00:00
|
|
|
addMatcher(fWarehouse.percent());
|
2018-02-10 10:01:46 +00:00
|
|
|
break;
|
|
|
|
case TYPE_PERMILLE:
|
2018-02-10 11:32:18 +00:00
|
|
|
addMatcher(fWarehouse.permille());
|
2018-02-10 10:01:46 +00:00
|
|
|
break;
|
|
|
|
case TYPE_CURRENCY_SINGLE:
|
|
|
|
case TYPE_CURRENCY_DOUBLE:
|
|
|
|
case TYPE_CURRENCY_TRIPLE:
|
|
|
|
case TYPE_CURRENCY_QUAD:
|
|
|
|
case TYPE_CURRENCY_QUINT:
|
|
|
|
// All currency symbols use the same matcher
|
2018-02-10 11:32:18 +00:00
|
|
|
addMatcher(fWarehouse.currency(status));
|
2018-02-10 10:01:46 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
U_ASSERT(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (fIgnorables != nullptr && fIgnorables->getSet()->contains(cp)) {
|
|
|
|
// Case 2: the token is an ignorable literal.
|
|
|
|
// No action necessary: the ignorables matcher has already been added.
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Case 3: the token is a non-ignorable literal.
|
2018-02-10 10:57:30 +00:00
|
|
|
addMatcher(fWarehouse.nextCodePointMatcher(cp));
|
2018-02-10 10:01:46 +00:00
|
|
|
}
|
|
|
|
fLastTypeOrCp = type != TYPE_CODEPOINT ? type : cp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AffixPatternMatcherBuilder::addMatcher(NumberParseMatcher& matcher) {
|
|
|
|
if (fMatchersLen >= fMatchers.getCapacity()) {
|
|
|
|
fMatchers.resize(fMatchersLen * 2, fMatchersLen);
|
|
|
|
}
|
|
|
|
fMatchers[fMatchersLen++] = &matcher;
|
|
|
|
}
|
|
|
|
|
|
|
|
AffixPatternMatcher AffixPatternMatcherBuilder::build() {
|
2018-02-10 10:57:30 +00:00
|
|
|
return AffixPatternMatcher(fMatchers, fMatchersLen, fPattern);
|
2018-02-10 10:01:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-10 10:57:30 +00:00
|
|
|
AffixTokenMatcherWarehouse::AffixTokenMatcherWarehouse(const UChar* currencyCode,
|
2018-02-10 14:29:26 +00:00
|
|
|
const UnicodeString* currency1,
|
|
|
|
const UnicodeString* currency2,
|
|
|
|
const DecimalFormatSymbols* dfs,
|
|
|
|
IgnorablesMatcher* ignorables, const Locale* locale)
|
2018-02-10 10:57:30 +00:00
|
|
|
: currency1(currency1),
|
|
|
|
currency2(currency2),
|
|
|
|
dfs(dfs),
|
|
|
|
ignorables(ignorables),
|
|
|
|
locale(locale),
|
|
|
|
codePointCount(0),
|
|
|
|
codePointNumBatches(0) {
|
2018-02-10 10:01:46 +00:00
|
|
|
utils::copyCurrencyCode(this->currencyCode, currencyCode);
|
|
|
|
}
|
|
|
|
|
2018-02-10 10:57:30 +00:00
|
|
|
AffixTokenMatcherWarehouse::~AffixTokenMatcherWarehouse() {
|
|
|
|
// Delete the variable number of batches of code point matchers
|
2018-02-10 11:32:18 +00:00
|
|
|
for (int32_t i = 0; i < codePointNumBatches; i++) {
|
2018-02-10 10:57:30 +00:00
|
|
|
delete[] codePointsOverflow[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-10 11:32:18 +00:00
|
|
|
NumberParseMatcher& AffixTokenMatcherWarehouse::minusSign() {
|
2018-02-10 14:29:26 +00:00
|
|
|
return fMinusSign = {*dfs, true};
|
2018-02-10 11:32:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NumberParseMatcher& AffixTokenMatcherWarehouse::plusSign() {
|
2018-02-10 14:29:26 +00:00
|
|
|
return fPlusSign = {*dfs, true};
|
2018-02-10 11:32:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NumberParseMatcher& AffixTokenMatcherWarehouse::percent() {
|
2018-02-10 14:29:26 +00:00
|
|
|
return fPercent = {*dfs};
|
2018-02-10 11:32:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NumberParseMatcher& AffixTokenMatcherWarehouse::permille() {
|
2018-02-10 14:29:26 +00:00
|
|
|
return fPermille = {*dfs};
|
2018-02-10 11:32:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NumberParseMatcher& AffixTokenMatcherWarehouse::currency(UErrorCode& status) {
|
2018-02-10 14:29:26 +00:00
|
|
|
return fCurrency = {{*locale, status}, {currencyCode, *currency1, *currency2}};
|
2018-02-10 11:32:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NumberParseMatcher& AffixTokenMatcherWarehouse::nextCodePointMatcher(UChar32 cp) {
|
2018-02-10 10:57:30 +00:00
|
|
|
if (codePointCount < CODE_POINT_STACK_CAPACITY) {
|
|
|
|
return codePoints[codePointCount++] = {cp};
|
|
|
|
}
|
|
|
|
int32_t totalCapacity = CODE_POINT_STACK_CAPACITY + codePointNumBatches * CODE_POINT_BATCH_SIZE;
|
|
|
|
if (codePointCount >= totalCapacity) {
|
|
|
|
// Need a new batch
|
|
|
|
auto* nextBatch = new CodePointMatcher[CODE_POINT_BATCH_SIZE];
|
|
|
|
if (codePointNumBatches >= codePointsOverflow.getCapacity()) {
|
|
|
|
// Need more room for storing pointers to batches
|
|
|
|
codePointsOverflow.resize(codePointNumBatches * 2, codePointNumBatches);
|
|
|
|
}
|
|
|
|
codePointsOverflow[codePointNumBatches++] = nextBatch;
|
|
|
|
}
|
|
|
|
return codePointsOverflow[codePointNumBatches - 1][(codePointCount++ - CODE_POINT_STACK_CAPACITY) %
|
2018-02-10 11:32:18 +00:00
|
|
|
CODE_POINT_BATCH_SIZE] = {cp};
|
2018-02-10 10:57:30 +00:00
|
|
|
}
|
|
|
|
|
2018-02-10 10:01:46 +00:00
|
|
|
|
|
|
|
CodePointMatcher::CodePointMatcher(UChar32 cp)
|
|
|
|
: fCp(cp) {}
|
|
|
|
|
|
|
|
bool CodePointMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode&) const {
|
|
|
|
if (segment.matches(fCp)) {
|
|
|
|
segment.adjustOffsetByCodePoint();
|
|
|
|
result.setCharsConsumed(segment);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const UnicodeSet& CodePointMatcher::getLeadCodePoints() {
|
|
|
|
if (fLocalLeadCodePoints.isNull()) {
|
|
|
|
auto* leadCodePoints = new UnicodeSet();
|
|
|
|
leadCodePoints->add(fCp);
|
|
|
|
leadCodePoints->freeze();
|
|
|
|
fLocalLeadCodePoints.adoptInstead(leadCodePoints);
|
|
|
|
}
|
|
|
|
return *fLocalLeadCodePoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-10 10:57:30 +00:00
|
|
|
AffixPatternMatcher AffixPatternMatcher::fromAffixPattern(const UnicodeString& affixPattern,
|
|
|
|
AffixTokenMatcherWarehouse& warehouse,
|
|
|
|
parse_flags_t parseFlags, bool* success,
|
|
|
|
UErrorCode& status) {
|
2018-02-10 10:01:46 +00:00
|
|
|
if (affixPattern.isEmpty()) {
|
|
|
|
*success = false;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
*success = true;
|
|
|
|
|
|
|
|
IgnorablesMatcher* ignorables;
|
|
|
|
if (0 != (parseFlags & PARSE_FLAG_EXACT_AFFIX)) {
|
|
|
|
ignorables = nullptr;
|
|
|
|
} else {
|
2018-02-10 10:57:30 +00:00
|
|
|
ignorables = warehouse.ignorables;
|
2018-02-10 10:01:46 +00:00
|
|
|
}
|
|
|
|
|
2018-02-10 10:57:30 +00:00
|
|
|
AffixPatternMatcherBuilder builder(affixPattern, warehouse, ignorables);
|
2018-02-10 10:01:46 +00:00
|
|
|
AffixUtils::iterateWithConsumer(UnicodeStringCharSequence(affixPattern), builder, status);
|
|
|
|
return builder.build();
|
|
|
|
}
|
|
|
|
|
|
|
|
AffixPatternMatcher::AffixPatternMatcher(MatcherArray& matchers, int32_t matchersLen,
|
2018-02-10 10:57:30 +00:00
|
|
|
const UnicodeString& pattern)
|
2018-02-10 14:29:26 +00:00
|
|
|
: ArraySeriesMatcher(matchers, matchersLen), fPattern(pattern) {}
|
|
|
|
|
|
|
|
UnicodeString AffixPatternMatcher::getPattern() const {
|
|
|
|
return fPattern.toAliasedUnicodeString();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AffixPatternMatcher::operator==(const AffixPatternMatcher& other) const {
|
|
|
|
return fPattern == other.fPattern;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AffixMatcherWarehouse::AffixMatcherWarehouse(const AffixPatternProvider& patternInfo,
|
|
|
|
NumberParserImpl& output,
|
|
|
|
AffixTokenMatcherWarehouse& warehouse,
|
|
|
|
const IgnorablesMatcher& ignorables, parse_flags_t parseFlags,
|
|
|
|
UErrorCode& status)
|
|
|
|
: fAffixTokenMatcherWarehouse(std::move(warehouse)) {
|
|
|
|
if (!isInteresting(patternInfo, ignorables, parseFlags, status)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The affixes have interesting characters, or we are in strict mode.
|
|
|
|
// Use initial capacity of 6, the highest possible number of AffixMatchers.
|
|
|
|
UnicodeString sb;
|
|
|
|
bool includeUnpaired = 0 != (parseFlags & PARSE_FLAG_INCLUDE_UNPAIRED_AFFIXES);
|
|
|
|
UNumberSignDisplay signDisplay = (0 != (parseFlags & PARSE_FLAG_PLUS_SIGN_ALLOWED)) ? UNUM_SIGN_ALWAYS
|
|
|
|
: UNUM_SIGN_NEVER;
|
|
|
|
|
|
|
|
int32_t numAffixMatchers = 0;
|
|
|
|
int32_t numAffixPatternMatchers = 0;
|
|
|
|
|
|
|
|
AffixPatternMatcher* posPrefix = nullptr;
|
|
|
|
AffixPatternMatcher* posSuffix = nullptr;
|
|
|
|
|
|
|
|
// Pre-process the affix strings to resolve LDML rules like sign display.
|
|
|
|
for (int8_t signum = 1; signum >= -1; signum--) {
|
|
|
|
// Generate Prefix
|
|
|
|
bool hasPrefix = false;
|
|
|
|
PatternStringUtils::patternInfoToStringBuilder(
|
|
|
|
patternInfo, true, signum, signDisplay, StandardPlural::OTHER, false, sb);
|
|
|
|
fAffixPatternMatchers[numAffixPatternMatchers] = AffixPatternMatcher::fromAffixPattern(
|
|
|
|
sb, warehouse, parseFlags, &hasPrefix, status);
|
|
|
|
AffixPatternMatcher* prefix = hasPrefix ? &fAffixPatternMatchers[numAffixPatternMatchers++]
|
|
|
|
: nullptr;
|
|
|
|
|
|
|
|
// Generate Suffix
|
|
|
|
bool hasSuffix = false;
|
|
|
|
PatternStringUtils::patternInfoToStringBuilder(
|
|
|
|
patternInfo, false, signum, signDisplay, StandardPlural::OTHER, false, sb);
|
|
|
|
fAffixPatternMatchers[numAffixPatternMatchers] = AffixPatternMatcher::fromAffixPattern(
|
|
|
|
sb, warehouse, parseFlags, &hasSuffix, status);
|
|
|
|
AffixPatternMatcher* suffix = hasSuffix ? &fAffixPatternMatchers[numAffixPatternMatchers++]
|
|
|
|
: nullptr;
|
|
|
|
|
|
|
|
if (signum == 1) {
|
|
|
|
posPrefix = prefix;
|
|
|
|
posSuffix = suffix;
|
|
|
|
} else if (equals(prefix, posPrefix) && equals(suffix, posSuffix)) {
|
|
|
|
// Skip adding these matchers (we already have equivalents)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flags for setting in the ParsedNumber
|
|
|
|
int flags = (signum == -1) ? FLAG_NEGATIVE : 0;
|
|
|
|
|
|
|
|
// Note: it is indeed possible for posPrefix and posSuffix to both be null.
|
|
|
|
// We still need to add that matcher for strict mode to work.
|
|
|
|
fAffixMatchers[numAffixMatchers++] = {prefix, suffix, flags};
|
|
|
|
if (includeUnpaired && prefix != nullptr && suffix != nullptr) {
|
|
|
|
// The following if statements are designed to prevent adding two identical matchers.
|
|
|
|
if (signum == 1 || equals(prefix, posPrefix)) {
|
|
|
|
fAffixMatchers[numAffixMatchers++] = {prefix, nullptr, flags};
|
|
|
|
}
|
|
|
|
if (signum == 1 || equals(suffix, posSuffix)) {
|
|
|
|
fAffixMatchers[numAffixMatchers++] = {nullptr, suffix, flags};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Put the AffixMatchers in order, and then add them to the output.
|
|
|
|
// TODO
|
|
|
|
// Collections.sort(matchers, COMPARATOR);
|
|
|
|
// output.addMatchers(matchers);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AffixMatcherWarehouse::isInteresting(const AffixPatternProvider& patternInfo,
|
|
|
|
const IgnorablesMatcher& ignorables, parse_flags_t parseFlags,
|
|
|
|
UErrorCode& status) {
|
|
|
|
UnicodeStringCharSequence posPrefixString(patternInfo.getString(AffixPatternProvider::AFFIX_POS_PREFIX));
|
|
|
|
UnicodeStringCharSequence posSuffixString(patternInfo.getString(AffixPatternProvider::AFFIX_POS_SUFFIX));
|
|
|
|
UnicodeStringCharSequence negPrefixString(UnicodeString(u""));
|
|
|
|
UnicodeStringCharSequence negSuffixString(UnicodeString(u""));
|
|
|
|
if (patternInfo.hasNegativeSubpattern()) {
|
|
|
|
negPrefixString = UnicodeStringCharSequence(patternInfo.getString(AffixPatternProvider::AFFIX_NEG_PREFIX));
|
|
|
|
negSuffixString = UnicodeStringCharSequence(patternInfo.getString(AffixPatternProvider::AFFIX_NEG_SUFFIX));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (0 == (parseFlags & PARSE_FLAG_USE_FULL_AFFIXES) &&
|
|
|
|
AffixUtils::containsOnlySymbolsAndIgnorables(posPrefixString, *ignorables.getSet(), status) &&
|
|
|
|
AffixUtils::containsOnlySymbolsAndIgnorables(posSuffixString, *ignorables.getSet(), status) &&
|
|
|
|
AffixUtils::containsOnlySymbolsAndIgnorables(negPrefixString, *ignorables.getSet(), status) &&
|
|
|
|
AffixUtils::containsOnlySymbolsAndIgnorables(negSuffixString, *ignorables.getSet(), status)
|
|
|
|
// HACK: Plus and minus sign are a special case: we accept them trailing only if they are
|
|
|
|
// trailing in the pattern string.
|
|
|
|
&& !AffixUtils::containsType(posSuffixString, TYPE_PLUS_SIGN, status) &&
|
|
|
|
!AffixUtils::containsType(posSuffixString, TYPE_MINUS_SIGN, status) &&
|
|
|
|
!AffixUtils::containsType(negSuffixString, TYPE_PLUS_SIGN, status) &&
|
|
|
|
!AffixUtils::containsType(negSuffixString, TYPE_MINUS_SIGN, status)) {
|
|
|
|
// The affixes contain only symbols and ignorables.
|
|
|
|
// No need to generate affix matchers.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AffixMatcherWarehouse::equals(const AffixPatternMatcher* lhs, const AffixPatternMatcher* rhs) {
|
|
|
|
if (lhs == nullptr && rhs == nullptr) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (lhs == nullptr || rhs == nullptr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return *lhs == *rhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AffixMatcher::AffixMatcher(AffixPatternMatcher* prefix, AffixPatternMatcher* suffix, result_flags_t flags)
|
|
|
|
: fPrefix(prefix), fSuffix(suffix), fFlags(flags) {}
|
|
|
|
|
|
|
|
bool AffixMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const {
|
|
|
|
if (!result.seenNumber()) {
|
|
|
|
// Prefix
|
|
|
|
// Do not match if:
|
|
|
|
// 1. We have already seen a prefix (result.prefix != null)
|
|
|
|
// 2. The prefix in this AffixMatcher is empty (prefix == null)
|
|
|
|
if (!result.prefix.isBogus() || fPrefix == nullptr) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to match the prefix.
|
|
|
|
int initialOffset = segment.getOffset();
|
|
|
|
bool maybeMore = fPrefix->match(segment, result, status);
|
|
|
|
if (initialOffset != segment.getOffset()) {
|
|
|
|
result.prefix = fPrefix->getPattern();
|
|
|
|
}
|
|
|
|
return maybeMore;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Suffix
|
|
|
|
// Do not match if:
|
|
|
|
// 1. We have already seen a suffix (result.suffix != null)
|
|
|
|
// 2. The suffix in this AffixMatcher is empty (suffix == null)
|
|
|
|
// 3. The matched prefix does not equal this AffixMatcher's prefix
|
|
|
|
if (!result.suffix.isBogus() || fSuffix == nullptr || !matched(fPrefix, result.prefix)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to match the suffix.
|
|
|
|
int initialOffset = segment.getOffset();
|
|
|
|
bool maybeMore = fSuffix->match(segment, result, status);
|
|
|
|
if (initialOffset != segment.getOffset()) {
|
|
|
|
result.suffix = fSuffix->getPattern();
|
|
|
|
}
|
|
|
|
return maybeMore;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const UnicodeSet& AffixMatcher::getLeadCodePoints() {
|
|
|
|
if (fLocalLeadCodePoints.isNull()) {
|
|
|
|
auto* leadCodePoints = new UnicodeSet();
|
|
|
|
if (fPrefix != nullptr) {
|
|
|
|
leadCodePoints->addAll(fPrefix->getLeadCodePoints());
|
|
|
|
}
|
|
|
|
if (fSuffix != nullptr) {
|
|
|
|
leadCodePoints->addAll(fSuffix->getLeadCodePoints());
|
|
|
|
}
|
|
|
|
leadCodePoints->freeze();
|
|
|
|
fLocalLeadCodePoints.adoptInstead(leadCodePoints);
|
|
|
|
}
|
|
|
|
return *fLocalLeadCodePoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AffixMatcher::postProcess(ParsedNumber& result) const {
|
|
|
|
// Check to see if our affix is the one that was matched. If so, set the flags in the result.
|
|
|
|
if (matched(fPrefix, result.prefix) && matched(fSuffix, result.suffix)) {
|
|
|
|
// Fill in the result prefix and suffix with non-null values (empty string).
|
|
|
|
// Used by strict mode to determine whether an entire affix pair was matched.
|
|
|
|
if (result.prefix.isBogus()) {
|
|
|
|
result.prefix = UnicodeString();
|
|
|
|
}
|
|
|
|
if (result.suffix.isBogus()) {
|
|
|
|
result.suffix = UnicodeString();
|
|
|
|
}
|
|
|
|
result.flags |= fFlags;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AffixMatcher::matched(const AffixPatternMatcher* affix, const UnicodeString& patternString) {
|
|
|
|
return (affix == nullptr && patternString.isBogus()) ||
|
|
|
|
(affix != nullptr && affix->getPattern() == patternString);
|
2018-02-10 10:01:46 +00:00
|
|
|
}
|
2018-02-10 06:36:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
#endif /* #if !UCONFIG_NO_FORMATTING */
|
2018-02-10 14:29:26 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|