11cb0ef41Sopenharmony_ci// © 2018 and later: Unicode, Inc. and others. 21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ci#include "unicode/utypes.h" 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci#if !UCONFIG_NO_FORMATTING 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci// Allow implicit conversion from char16_t* to UnicodeString for this file: 91cb0ef41Sopenharmony_ci// Helpful in toString methods and elsewhere. 101cb0ef41Sopenharmony_ci#define UNISTR_FROM_STRING_EXPLICIT 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci#include "numparse_types.h" 131cb0ef41Sopenharmony_ci#include "numparse_compositions.h" 141cb0ef41Sopenharmony_ci#include "string_segment.h" 151cb0ef41Sopenharmony_ci#include "unicode/uniset.h" 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ciusing namespace icu; 181cb0ef41Sopenharmony_ciusing namespace icu::numparse; 191cb0ef41Sopenharmony_ciusing namespace icu::numparse::impl; 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_cibool SeriesMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const { 231cb0ef41Sopenharmony_ci ParsedNumber backup(result); 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ci int32_t initialOffset = segment.getOffset(); 261cb0ef41Sopenharmony_ci bool maybeMore = true; 271cb0ef41Sopenharmony_ci for (auto* it = begin(); it < end();) { 281cb0ef41Sopenharmony_ci const NumberParseMatcher* matcher = *it; 291cb0ef41Sopenharmony_ci int matcherOffset = segment.getOffset(); 301cb0ef41Sopenharmony_ci if (segment.length() != 0) { 311cb0ef41Sopenharmony_ci maybeMore = matcher->match(segment, result, status); 321cb0ef41Sopenharmony_ci } else { 331cb0ef41Sopenharmony_ci // Nothing for this matcher to match; ask for more. 341cb0ef41Sopenharmony_ci maybeMore = true; 351cb0ef41Sopenharmony_ci } 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci bool success = (segment.getOffset() != matcherOffset); 381cb0ef41Sopenharmony_ci bool isFlexible = matcher->isFlexible(); 391cb0ef41Sopenharmony_ci if (success && isFlexible) { 401cb0ef41Sopenharmony_ci // Match succeeded, and this is a flexible matcher. Re-run it. 411cb0ef41Sopenharmony_ci } else if (success) { 421cb0ef41Sopenharmony_ci // Match succeeded, and this is NOT a flexible matcher. Proceed to the next matcher. 431cb0ef41Sopenharmony_ci it++; 441cb0ef41Sopenharmony_ci // Small hack: if there is another matcher coming, do not accept trailing weak chars. 451cb0ef41Sopenharmony_ci // Needed for proper handling of currency spacing. 461cb0ef41Sopenharmony_ci if (it < end() && segment.getOffset() != result.charEnd && result.charEnd > matcherOffset) { 471cb0ef41Sopenharmony_ci segment.setOffset(result.charEnd); 481cb0ef41Sopenharmony_ci } 491cb0ef41Sopenharmony_ci } else if (isFlexible) { 501cb0ef41Sopenharmony_ci // Match failed, and this is a flexible matcher. Try again with the next matcher. 511cb0ef41Sopenharmony_ci it++; 521cb0ef41Sopenharmony_ci } else { 531cb0ef41Sopenharmony_ci // Match failed, and this is NOT a flexible matcher. Exit. 541cb0ef41Sopenharmony_ci segment.setOffset(initialOffset); 551cb0ef41Sopenharmony_ci result = backup; 561cb0ef41Sopenharmony_ci return maybeMore; 571cb0ef41Sopenharmony_ci } 581cb0ef41Sopenharmony_ci } 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci // All matchers in the series succeeded. 611cb0ef41Sopenharmony_ci return maybeMore; 621cb0ef41Sopenharmony_ci} 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_cibool SeriesMatcher::smokeTest(const StringSegment& segment) const { 651cb0ef41Sopenharmony_ci // NOTE: The range-based for loop calls the virtual begin() and end() methods. 661cb0ef41Sopenharmony_ci // NOTE: We only want the first element. Use the for loop for boundary checking. 671cb0ef41Sopenharmony_ci for (auto& matcher : *this) { 681cb0ef41Sopenharmony_ci // SeriesMatchers are never allowed to start with a Flexible matcher. 691cb0ef41Sopenharmony_ci U_ASSERT(!matcher->isFlexible()); 701cb0ef41Sopenharmony_ci return matcher->smokeTest(segment); 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci return false; 731cb0ef41Sopenharmony_ci} 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_civoid SeriesMatcher::postProcess(ParsedNumber& result) const { 761cb0ef41Sopenharmony_ci // NOTE: The range-based for loop calls the virtual begin() and end() methods. 771cb0ef41Sopenharmony_ci for (auto* matcher : *this) { 781cb0ef41Sopenharmony_ci matcher->postProcess(result); 791cb0ef41Sopenharmony_ci } 801cb0ef41Sopenharmony_ci} 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ciArraySeriesMatcher::ArraySeriesMatcher() 841cb0ef41Sopenharmony_ci : fMatchersLen(0) { 851cb0ef41Sopenharmony_ci} 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ciArraySeriesMatcher::ArraySeriesMatcher(MatcherArray& matchers, int32_t matchersLen) 881cb0ef41Sopenharmony_ci : fMatchers(std::move(matchers)), fMatchersLen(matchersLen) { 891cb0ef41Sopenharmony_ci} 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ciint32_t ArraySeriesMatcher::length() const { 921cb0ef41Sopenharmony_ci return fMatchersLen; 931cb0ef41Sopenharmony_ci} 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ciconst NumberParseMatcher* const* ArraySeriesMatcher::begin() const { 961cb0ef41Sopenharmony_ci return fMatchers.getAlias(); 971cb0ef41Sopenharmony_ci} 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ciconst NumberParseMatcher* const* ArraySeriesMatcher::end() const { 1001cb0ef41Sopenharmony_ci return fMatchers.getAlias() + fMatchersLen; 1011cb0ef41Sopenharmony_ci} 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ciUnicodeString ArraySeriesMatcher::toString() const { 1041cb0ef41Sopenharmony_ci return u"<ArraySeries>"; 1051cb0ef41Sopenharmony_ci} 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */ 109