From e3180662e2dc53fa343018ce72e5ce7a7b10f56c Mon Sep 17 00:00:00 2001 From: Shane Carr Date: Wed, 21 Mar 2018 09:48:55 +0000 Subject: [PATCH] ICU-13634 Parsing wrapper is working; data-driven file is updated and passing. The C++ and Java implementations have almost identical behavior according to the data-driven test file, with the only differences seeming to involve overflow and extremely large numbers. X-SVN-Rev: 41134 --- icu4c/source/i18n/decimfmt.cpp | 99 ++++++-- icu4c/source/i18n/numparse_impl.cpp | 5 +- icu4c/source/i18n/numparse_parsednumber.cpp | 35 +++ icu4c/source/i18n/numparse_types.h | 4 +- icu4c/source/i18n/unicode/decimfmt.h | 41 +++- icu4c/source/i18n/unicode/unum.h | 16 +- .../datadrivennumberformattestsuite.cpp | 2 +- icu4c/source/test/intltest/numfmtst.cpp | 10 +- .../numberformattestspecification.txt | 216 +++++++++--------- 9 files changed, 291 insertions(+), 137 deletions(-) diff --git a/icu4c/source/i18n/decimfmt.cpp b/icu4c/source/i18n/decimfmt.cpp index 510039e86b8..5fd757daeef 100644 --- a/icu4c/source/i18n/decimfmt.cpp +++ b/icu4c/source/i18n/decimfmt.cpp @@ -190,6 +190,14 @@ DecimalFormat::setAttribute(UNumberFormatAttribute attr, int32_t newValue, UErro setMinimumGroupingDigits(newValue); break; + case UNUM_PARSE_CASE_SENSITIVE: + setParseCaseSensitive(static_cast(newValue)); + break; + + case UNUM_SIGN_ALWAYS_SHOWN: + setSignAlwaysShown(static_cast(newValue)); + break; + default: status = U_UNSUPPORTED_ERROR; break; @@ -262,7 +270,7 @@ int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr, UErrorCode& sta return getSecondaryGroupingSize(); case UNUM_PARSE_NO_EXPONENT: - return getParseNoExponent(); + return isParseNoExponent(); case UNUM_PARSE_DECIMAL_MARK_REQUIRED: return isDecimalPatternMatchRequired(); @@ -273,6 +281,12 @@ int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr, UErrorCode& sta case UNUM_MINIMUM_GROUPING_DIGITS: return getMinimumGroupingDigits(); + case UNUM_PARSE_CASE_SENSITIVE: + return isParseCaseSensitive(); + + case UNUM_SIGN_ALWAYS_SHOWN: + return isSignAlwaysShown(); + default: status = U_UNSUPPORTED_ERROR; break; @@ -296,10 +310,17 @@ void DecimalFormat::setGroupingUsed(UBool enabled) { } void DecimalFormat::setParseIntegerOnly(UBool value) { + NumberFormat::setParseIntegerOnly(value); // to set field for compatibility fProperties->parseIntegerOnly = value; refreshFormatterNoError(); } +void DecimalFormat::setLenient(UBool enable) { + NumberFormat::setLenient(enable); // to set field for compatibility + fProperties->parseMode = enable ? PARSE_MODE_LENIENT : PARSE_MODE_STRICT; + refreshFormatterNoError(); +} + DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, UParseError&, UErrorCode& status) : DecimalFormat(symbolsToAdopt, status) { @@ -450,14 +471,46 @@ DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, Fi return appendTo; } -void DecimalFormat::parse(const UnicodeString& /*text*/, Formattable& /*result*/, - ParsePosition& /*parsePosition*/) const { - // FIXME +void DecimalFormat::parse(const UnicodeString& text, Formattable& output, + ParsePosition& parsePosition) const { + if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) { + return; + } + + ErrorCode status; + ParsedNumber result; + // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the + // parseCurrency method (backwards compatibility) + int32_t startIndex = parsePosition.getIndex(); + fParser->parse(text, startIndex, true, result, status); + if (result.success()) { + parsePosition.setIndex(result.charEnd); + result.populateFormattable(output); + } else { + parsePosition.setErrorIndex(startIndex + result.charEnd); + } } -CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& /*text*/, ParsePosition& /*pos*/) const { - // FIXME - return nullptr; +CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, ParsePosition& parsePosition) const { + if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) { + return nullptr; + } + + ErrorCode status; + ParsedNumber result; + // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the + // parseCurrency method (backwards compatibility) + int32_t startIndex = parsePosition.getIndex(); + fParserWithCurrency->parse(text, startIndex, true, result, status); + if (result.success()) { + parsePosition.setIndex(result.charEnd); + Formattable formattable; + result.populateFormattable(formattable); + return new CurrencyAmount(formattable, result.currencyCode, status); + } else { + parsePosition.setErrorIndex(startIndex + result.charEnd); + return nullptr; + } } const DecimalFormatSymbols* DecimalFormat::getDecimalFormatSymbols(void) const { @@ -535,6 +588,15 @@ void DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) { refreshFormatterNoError(); } +UBool DecimalFormat::isSignAlwaysShown() const { + return fProperties->signAlwaysShown; +} + +void DecimalFormat::setSignAlwaysShown(UBool value) { + fProperties->signAlwaysShown = value; + refreshFormatterNoError(); +} + int32_t DecimalFormat::getMultiplier(void) const { if (fProperties->multiplier != 1) { return fProperties->multiplier; @@ -708,7 +770,7 @@ void DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) { refreshFormatterNoError(); } -UBool DecimalFormat::getParseNoExponent() const { +UBool DecimalFormat::isParseNoExponent() const { return fProperties->parseNoExponent; } @@ -717,6 +779,15 @@ void DecimalFormat::setParseNoExponent(UBool value) { refreshFormatterNoError(); } +UBool DecimalFormat::isParseCaseSensitive() const { + return fProperties->parseCaseSensitive; +} + +void DecimalFormat::setParseCaseSensitive(UBool value) { + fProperties->parseCaseSensitive = value; + refreshFormatterNoError(); +} + UnicodeString& DecimalFormat::toPattern(UnicodeString& result) const { // Pull some properties from exportedProperties and others from properties // to keep affix patterns intact. In particular, pull rounding properties @@ -907,13 +978,13 @@ void DecimalFormat::refreshFormatter(UErrorCode& status) { *fProperties, *fSymbols, *fWarehouse, *fExportedProperties, status).locale( locale)), status); - // fParser.adoptInsteadAndCheckErrorCode( - // NumberParserImpl::createParserFromProperties( - // *fProperties, *fSymbols, false, false, status), status); + fParser.adoptInsteadAndCheckErrorCode( + NumberParserImpl::createParserFromProperties( + *fProperties, *fSymbols, false, status), status); - // fParserWithCurrency.adoptInsteadAndCheckErrorCode( - // NumberParserImpl::createParserFromProperties( - // *fProperties, *fSymbols, true, false, status), status); + fParserWithCurrency.adoptInsteadAndCheckErrorCode( + NumberParserImpl::createParserFromProperties( + *fProperties, *fSymbols, true, status), status); } void DecimalFormat::refreshFormatterNoError() { diff --git a/icu4c/source/i18n/numparse_impl.cpp b/icu4c/source/i18n/numparse_impl.cpp index e894a1eaabe..d8338ae0cf9 100644 --- a/icu4c/source/i18n/numparse_impl.cpp +++ b/icu4c/source/i18n/numparse_impl.cpp @@ -112,10 +112,13 @@ NumberParserImpl::createParserFromProperties(const number::impl::DecimalFormatPr if (parseCurrency || patternInfo.hasCurrencySign()) { parseFlags |= PARSE_FLAG_MONETARY_SEPARATORS; } - IgnorablesMatcher ignorables(isStrict ? unisets::DEFAULT_IGNORABLES : unisets::STRICT_IGNORABLES); LocalPointer parser(new NumberParserImpl(parseFlags)); + parser->fLocalMatchers.ignorables = { + isStrict ? unisets::STRICT_IGNORABLES : unisets::DEFAULT_IGNORABLES}; + IgnorablesMatcher& ignorables = parser->fLocalMatchers.ignorables; + ////////////////////// /// AFFIX MATCHERS /// ////////////////////// diff --git a/icu4c/source/i18n/numparse_parsednumber.cpp b/icu4c/source/i18n/numparse_parsednumber.cpp index c9b68a245e5..b9cc54e6272 100644 --- a/icu4c/source/i18n/numparse_parsednumber.cpp +++ b/icu4c/source/i18n/numparse_parsednumber.cpp @@ -10,9 +10,12 @@ #define UNISTR_FROM_STRING_EXPLICIT #include "numparse_types.h" +#include "number_decimalquantity.h" #include using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; using namespace icu::numparse; using namespace icu::numparse::impl; @@ -78,6 +81,38 @@ double ParsedNumber::getDouble() const { return d; } +void ParsedNumber::populateFormattable(Formattable& output) const { + bool sawNegative = 0 != (flags & FLAG_NEGATIVE); + bool sawNaN = 0 != (flags & FLAG_NAN); + bool sawInfinity = 0 != (flags & FLAG_INFINITY); + + // Check for NaN, infinity, and -0.0 + if (sawNaN) { + output.setDouble(NAN); + return; + } + if (sawInfinity) { + if (sawNegative) { + output.setDouble(-INFINITY); + return; + } else { + output.setDouble(INFINITY); + return; + } + } + if (quantity.isZero() && sawNegative) { + output.setDouble(-0.0); + return; + } + + // All other numbers + LocalPointer actualQuantity(new DecimalQuantity(quantity)); + if (0 != (flags & FLAG_NEGATIVE)) { + actualQuantity->multiplyBy(-1); + } + output.adoptDecimalQuantity(actualQuantity.orphan()); +} + bool ParsedNumber::isBetterThan(const ParsedNumber& other) { // Favor results with strictly more characters consumed. return charEnd > other.charEnd; diff --git a/icu4c/source/i18n/numparse_types.h b/icu4c/source/i18n/numparse_types.h index 2f8d31fc76f..dfaadd9cb9e 100644 --- a/icu4c/source/i18n/numparse_types.h +++ b/icu4c/source/i18n/numparse_types.h @@ -46,7 +46,7 @@ enum ParseFlags { PARSE_FLAG_USE_FULL_AFFIXES = 0x0100, PARSE_FLAG_EXACT_AFFIX = 0x0200, PARSE_FLAG_PLUS_SIGN_ALLOWED = 0x0400, - PARSE_FLAG_OPTIMIZE = 0x0800, + // PARSE_FLAG_OPTIMIZE = 0x0800, // no longer used }; @@ -156,6 +156,8 @@ class ParsedNumber { double getDouble() const; + void populateFormattable(Formattable& output) const; + bool isBetterThan(const ParsedNumber& other); }; diff --git a/icu4c/source/i18n/unicode/decimfmt.h b/icu4c/source/i18n/unicode/decimfmt.h index 75dc8d5f44b..dcae4e2ae0b 100644 --- a/icu4c/source/i18n/unicode/decimfmt.h +++ b/icu4c/source/i18n/unicode/decimfmt.h @@ -822,6 +822,15 @@ class U_I18N_API DecimalFormat : public NumberFormat { */ void setParseIntegerOnly(UBool value) U_OVERRIDE; + /** + * Sets whether lenient parsing should be enabled (it is off by default). + * + * @param enable \c TRUE if lenient parsing should be used, + * \c FALSE otherwise. + * @stable ICU 4.8 + */ + void setLenient(UBool enable) U_OVERRIDE; + /** * Create a DecimalFormat from the given pattern and symbols. * Use this constructor when you need to completely customize the @@ -1266,6 +1275,19 @@ class U_I18N_API DecimalFormat : public NumberFormat { */ virtual void setNegativeSuffix(const UnicodeString& newValue); + /** + * Whether to show the plus sign on positive (non-negative) numbers; for example, "+12" + * @internal Technical Preview + */ + UBool isSignAlwaysShown() const; + + /** + * Set whether to show the plus sign on positive (non-negative) numbers; for example, "+12" + * @param value The new setting for whether to show plus sign on positive numbers + * @internal Technical Preview + */ + void setSignAlwaysShown(UBool value); + /** * Get the multiplier for use in percent, permill, etc. * For a percentage, set the suffixes to have "%" and the multiplier to be 100. @@ -1655,7 +1677,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { * @see #setParseNoExponent * @internal This API is a technical preview. It may change in an upcoming release. */ - UBool getParseNoExponent() const; + UBool isParseNoExponent() const; /** * {@icu} Specifies whether to stop parsing when an exponent separator is encountered. For @@ -1667,6 +1689,23 @@ class U_I18N_API DecimalFormat : public NumberFormat { */ void setParseNoExponent(UBool value); + /** + * {@icu} Returns whether parsing is sensitive to case (lowercase/uppercase). + * + * @see #setParseCaseSensitive + * @internal This API is a technical preview. It may change in an upcoming release. + */ + UBool isParseCaseSensitive() const; + + /** + * {@icu} Whether to pay attention to case when parsing; default is to ignore case (perform + * case-folding). For example, "A" == "a" in case-insensitive but not case-sensitive mode. + * + * Currency codes are never case-folded. For example, "us$1.00" will not parse in case-insensitive + * mode, even though "US$1.00" parses. + */ + void setParseCaseSensitive(UBool value); + /** * Synthesizes a pattern string that represents the current state diff --git a/icu4c/source/i18n/unicode/unum.h b/icu4c/source/i18n/unicode/unum.h index ff251ff2699..99864a169ba 100644 --- a/icu4c/source/i18n/unicode/unum.h +++ b/icu4c/source/i18n/unicode/unum.h @@ -1052,7 +1052,7 @@ typedef enum UNumberFormatAttribute { * Default: 0 (unset) * @stable ICU 50 */ - UNUM_PARSE_NO_EXPONENT, + UNUM_PARSE_NO_EXPONENT = 0x1001, /** * if this attribute is set to 1, specifies that, if the pattern contains a @@ -1067,7 +1067,19 @@ typedef enum UNumberFormatAttribute { /* The following cannot be #ifndef U_HIDE_INTERNAL_API, needed in .h file variable declararions */ /** Limit of boolean attributes. * @internal */ - UNUM_LIMIT_BOOLEAN_ATTRIBUTE = 0x1003 + UNUM_LIMIT_BOOLEAN_ATTRIBUTE = 0x1003, + + /** + * Whether parsing is sensitive to case (lowercase/uppercase). + * @internal This API is a technical preview. It may change in an upcoming release. + */ + UNUM_PARSE_CASE_SENSITIVE = 0x1004, + + /** + * Formatting: whether to show the plus sign on non-negative numbers. + * @internal This API is a technical preview. It may change in an upcoming release. + */ + UNUM_SIGN_ALWAYS_SHOWN = 0x1005, } UNumberFormatAttribute; /** diff --git a/icu4c/source/test/intltest/datadrivennumberformattestsuite.cpp b/icu4c/source/test/intltest/datadrivennumberformattestsuite.cpp index 9af8fdfd520..c8f10d13264 100644 --- a/icu4c/source/test/intltest/datadrivennumberformattestsuite.cpp +++ b/icu4c/source/test/intltest/datadrivennumberformattestsuite.cpp @@ -99,7 +99,7 @@ void DataDrivenNumberFormatTestSuite::run(const char *fileName, UBool runAllTest : breaksC(); UBool actualSuccess = isPass(fTuple, errorMessage, status); if (shouldFail && actualSuccess) { - showFailure("Expected failure, but passed"); + showFailure("Expected failure, but passed: " + errorMessage); break; } else if (!shouldFail && !actualSuccess) { showFailure(errorMessage); diff --git a/icu4c/source/test/intltest/numfmtst.cpp b/icu4c/source/test/intltest/numfmtst.cpp index 46e119756ac..35825b62cf3 100644 --- a/icu4c/source/test/intltest/numfmtst.cpp +++ b/icu4c/source/test/intltest/numfmtst.cpp @@ -231,7 +231,7 @@ static void adjustDecimalFormat( fmt.setNegativeSuffix(tuple.negativeSuffix); } if (tuple.signAlwaysShownFlag) { - // Not currently supported + fmt.setSignAlwaysShown(tuple.signAlwaysShown != 0); } if (tuple.localizedPatternFlag) { UErrorCode status = U_ZERO_ERROR; @@ -259,7 +259,7 @@ static void adjustDecimalFormat( } } if (tuple.parseCaseSensitiveFlag) { - // TODO: Fill this in when support is added in ICU4C + fmt.setParseCaseSensitive(tuple.parseCaseSensitive != 0); } } @@ -403,8 +403,6 @@ UBool NumberFormatTestDataDriven::isParsePass( const NumberFormatTestTuple &tuple, UnicodeString &appendErrorMessage, UErrorCode &status) { - return TRUE; -#if 0 if (U_FAILURE(status)) { return FALSE; } @@ -460,15 +458,12 @@ UBool NumberFormatTestDataDriven::isParsePass( return FALSE; } return TRUE; -#endif } UBool NumberFormatTestDataDriven::isParseCurrencyPass( const NumberFormatTestTuple &tuple, UnicodeString &appendErrorMessage, UErrorCode &status) { - return TRUE; -#if 0 if (U_FAILURE(status)) { return FALSE; } @@ -512,7 +507,6 @@ UBool NumberFormatTestDataDriven::isParseCurrencyPass( return FALSE; } return TRUE; -#endif } //#define NUMFMTST_CACHE_DEBUG 1 diff --git a/icu4c/source/test/testdata/numberformattestspecification.txt b/icu4c/source/test/testdata/numberformattestspecification.txt index f74a6566aa7..8aa1bb44ea2 100644 --- a/icu4c/source/test/testdata/numberformattestspecification.txt +++ b/icu4c/source/test/testdata/numberformattestspecification.txt @@ -736,7 +736,7 @@ parse output breaks 5,347.25 5347.25 JK (5,347.25 -5347.25 J // S is successful at parsing this as -5347.25 in lenient mode --5,347.25 -5347.25 CJK +-5,347.25 -5347.25 JK +3.52E4 35200 (34.8E-3) -0.0348 // JDK stops parsing at the spaces. JDK doesn't see space as a grouping separator @@ -745,7 +745,7 @@ parse output breaks // J doesn't allow trailing separators before E but C does (34,,25,E-1) -342.5 J (34 25 E-1) -342.5 JK -(34,,25 E-1) -342.5 CJK +(34,,25 E-1) -342.5 JK // Spaces are not allowed after exponent symbol // C parses up to the E but J bails (34 25E -1) -3425 JK @@ -796,16 +796,14 @@ set locale en set pattern #,##0.0###+;#- begin parse output breaks -// C sees this as -3426, don't understand why. // J and K just bail. -3426 3426 JKC +3426 3426 JK 3426+ 3426 -// J bails; C and K see -34 -34 d1+ 34 JKC +// J bails; K sees -34 +34 d1+ 34 JK // JDK sees this as -1234 for some reason // J bails b/c of trailing separators -// C parses until trailing separators, but sees -1234 -1,234,,,+ 1234 JKC +1,234,,,+ 1234 JK 1,234- -1234 // J bails because of trailing separators 1,234,- -1234 J @@ -861,8 +859,8 @@ parse output breaks +1,234.5 1234.5 // Comma after decimal means parse to a comma +1,23,456.78,9 123456.78 -// C and J fail upon seeing the second decimal point -+1,23,456.78.9 123456.78 CJ +// J fails upon seeing the second decimal point ++1,23,456.78.9 123456.78 J +79 79 +79 79 + 79 fail @@ -875,10 +873,10 @@ set pattern #E0 set lenient 0 begin parse output breaks -123 fail CJK +123 fail JK 123E1 1230 123E0 123 -123E fail CJK +123E fail JK test parse strict without prefix/suffix set locale en @@ -900,7 +898,7 @@ begin parse output breaks 35 35 // S accepts leading plus signs -+35 35 CJK ++35 35 JK -35 -35 2.63 2 -39.99 -39 @@ -1027,19 +1025,19 @@ $53.45 fail USD J 53.45 USD 53.45 USD 53.45 GBP 53.45 GBP USD 53.45 53.45 USD J -53.45USD 53.45 USD CJ +53.45USD 53.45 USD J USD53.45 53.45 USD (7.92) USD -7.92 USD (7.92) GBP -7.92 GBP (7.926) USD -7.926 USD -(7.926 USD) -7.926 USD CJ -(USD 7.926) -7.926 USD CJ -USD (7.926) -7.926 USD CJ -USD (7.92) -7.92 USD CJ -(7.92)USD -7.92 USD CJ -USD(7.92) -7.92 USD CJ +(7.926 USD) -7.926 USD J +(USD 7.926) -7.926 USD J +USD (7.926) -7.926 USD J +USD (7.92) -7.92 USD J +(7.92)USD -7.92 USD J +USD(7.92) -7.92 USD J (8) USD -8 USD --8 USD -8 USD C +-8 USD -8 USD 67 USD 67 USD 53.45$ fail USD US Dollars 53.45 53.45 USD J @@ -1047,20 +1045,20 @@ US Dollars 53.45 53.45 USD J US Dollar 53.45 53.45 USD J 53.45 US Dollar 53.45 USD US Dollars53.45 53.45 USD -53.45US Dollars 53.45 USD CJ +53.45US Dollars 53.45 USD J US Dollar53.45 53.45 USD US Dollat53.45 fail USD -53.45US Dollar 53.45 USD CJ -US Dollars (53.45) -53.45 USD CJ +53.45US Dollar 53.45 USD J +US Dollars (53.45) -53.45 USD J (53.45) US Dollars -53.45 USD (53.45) Euros -53.45 EUR -US Dollar (53.45) -53.45 USD CJ +US Dollar (53.45) -53.45 USD J (53.45) US Dollar -53.45 USD -US Dollars(53.45) -53.45 USD CJ -(53.45)US Dollars -53.45 USD CJ -US Dollar(53.45) -53.45 USD CJ +US Dollars(53.45) -53.45 USD J +(53.45)US Dollars -53.45 USD J +US Dollar(53.45) -53.45 USD J US Dollat(53.45) fail USD -(53.45)US Dollar -53.45 USD CJ +(53.45)US Dollar -53.45 USD J test parse currency ISO negative @@ -1074,14 +1072,14 @@ $53.45 fail USD J 53.45 USD 53.45 USD 53.45 GBP 53.45 GBP USD 53.45 53.45 USD J -53.45USD 53.45 USD CJ +53.45USD 53.45 USD J USD53.45 53.45 USD -7.92 USD -7.92 USD -7.92 GBP -7.92 GBP -7.926 USD -7.926 USD -USD -7.926 -7.926 USD CJ --7.92USD -7.92 USD CJ -USD-7.92 -7.92 USD CJ +USD -7.926 -7.926 USD J +-7.92USD -7.92 USD J +USD-7.92 -7.92 USD J -8 USD -8 USD 67 USD 67 USD 53.45$ fail USD @@ -1090,10 +1088,10 @@ US Dollars 53.45 53.45 USD J US Dollar 53.45 53.45 USD J 53.45 US Dollar 53.45 USD US Dollars53.45 53.45 USD -53.45US Dollars 53.45 USD CJ +53.45US Dollars 53.45 USD J US Dollar53.45 53.45 USD US Dollat53.45 fail USD -53.45US Dollar 53.45 USD CJ +53.45US Dollar 53.45 USD J test parse currency long @@ -1108,19 +1106,19 @@ $53.45 fail USD J 53.45 USD 53.45 USD 53.45 GBP 53.45 GBP USD 53.45 53.45 USD J -53.45USD 53.45 USD CJ +53.45USD 53.45 USD J USD53.45 53.45 USD (7.92) USD -7.92 USD (7.92) GBP -7.92 GBP (7.926) USD -7.926 USD -(7.926 USD) -7.926 USD CJ -(USD 7.926) -7.926 USD CJ -USD (7.926) -7.926 USD CJ -USD (7.92) -7.92 USD CJ -(7.92)USD -7.92 USD CJ -USD(7.92) -7.92 USD CJ +(7.926 USD) -7.926 USD J +(USD 7.926) -7.926 USD J +USD (7.926) -7.926 USD J +USD (7.92) -7.92 USD J +(7.92)USD -7.92 USD J +USD(7.92) -7.92 USD J (8) USD -8 USD --8 USD -8 USD C +-8 USD -8 USD 67 USD 67 USD // J throws a NullPointerException on the next case 53.45$ fail USD @@ -1129,10 +1127,10 @@ US Dollars 53.45 53.45 USD J US Dollar 53.45 53.45 USD J 53.45 US Dollar 53.45 USD US Dollars53.45 53.45 USD -53.45US Dollars 53.45 USD CJ +53.45US Dollars 53.45 USD J US Dollar53.45 53.45 USD US Dollat53.45 fail USD -53.45US Dollar 53.45 USD CJ +53.45US Dollar 53.45 USD J test parse currency short @@ -1146,19 +1144,19 @@ $53.45 fail USD J 53.45 USD 53.45 USD 53.45 GBP 53.45 GBP USD 53.45 53.45 USD J -53.45USD 53.45 USD CJ +53.45USD 53.45 USD J USD53.45 53.45 USD (7.92) USD -7.92 USD (7.92) GBP -7.92 GBP (7.926) USD -7.926 USD -(7.926 USD) -7.926 USD CJ -(USD 7.926) -7.926 USD CJ -USD (7.926) -7.926 USD CJ -USD (7.92) -7.92 USD CJ -(7.92)USD -7.92 USD CJ -USD(7.92) -7.92 USD CJ +(7.926 USD) -7.926 USD J +(USD 7.926) -7.926 USD J +USD (7.926) -7.926 USD J +USD (7.92) -7.92 USD J +(7.92)USD -7.92 USD J +USD(7.92) -7.92 USD J (8) USD -8 USD --8 USD -8 USD C +-8 USD -8 USD 67 USD 67 USD 53.45$ fail USD US Dollars 53.45 53.45 USD J @@ -1166,10 +1164,10 @@ US Dollars 53.45 53.45 USD J US Dollar 53.45 53.45 USD J 53.45 US Dollar 53.45 USD US Dollars53.45 53.45 USD -53.45US Dollars 53.45 USD CJ +53.45US Dollars 53.45 USD J US Dollar53.45 53.45 USD US Dollat53.45 fail USD -53.45US Dollar 53.45 USD CJ +53.45US Dollar 53.45 USD J test parse currency short prefix @@ -1180,12 +1178,12 @@ parse output outputCurrency breaks 53.45 fail GBP £53.45 53.45 GBP $53.45 fail USD J -53.45 USD 53.45 USD C -53.45 GBP 53.45 GBP C +53.45 USD 53.45 USD +53.45 GBP 53.45 GBP USD 53.45 53.45 USD J -53.45USD 53.45 USD CJ +53.45USD 53.45 USD J USD53.45 53.45 USD -// P fails these because '(' is an incomplete prefix. +// C and P fail these because '(' is an incomplete prefix. (7.92) USD -7.92 USD CJP (7.92) GBP -7.92 GBP CJP (7.926) USD -7.926 USD CJP @@ -1196,17 +1194,17 @@ USD (7.92) -7.92 USD CJP (7.92)USD -7.92 USD CJP USD(7.92) -7.92 USD CJP (8) USD -8 USD CJP --8 USD -8 USD C -67 USD 67 USD C +-8 USD -8 USD +67 USD 67 USD 53.45$ fail USD US Dollars 53.45 53.45 USD J 53.45 US Dollars 53.45 USD US Dollar 53.45 53.45 USD J 53.45 US Dollar 53.45 USD US Dollars53.45 53.45 USD -53.45US Dollars 53.45 USD CJ +53.45US Dollars 53.45 USD J US Dollar53.45 53.45 USD -53.45US Dollar 53.45 USD CJ +53.45US Dollar 53.45 USD J test format foreign currency set locale fa_IR @@ -1225,10 +1223,10 @@ parse output outputCurrency breaks \u0631\u06cc\u0627\u0644 \u06F1\u06F2\u06F3\u06F5 1235 IRR IRR \u06F1\u06F2\u06F3\u06F5 1235 IRR // P fails here because this currency name is in the Trie only, but it has the same prefix as the non-Trie currency -\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 \u06F1\u06F2\u06F3\u06F5 1235 IRR P +\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 \u06F1\u06F2\u06F3\u06F5 1235 IRR CP IRR 1235 1235 IRR \u0631\u06cc\u0627\u0644 1235 1235 IRR -\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235 1235 IRR P +\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235 1235 IRR CP test parse foreign currency ISO set pattern \u00a4\u00a4 0.00;\u00a4\u00a4 -# @@ -1237,10 +1235,10 @@ begin parse output outputCurrency breaks \u0631\u06cc\u0627\u0644 \u06F1\u06F2\u06F3\u06F5 1235 IRR IRR \u06F1\u06F2\u06F3\u06F5 1235 IRR -\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 \u06F1\u06F2\u06F3\u06F5 1235 IRR P +\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 \u06F1\u06F2\u06F3\u06F5 1235 IRR CP IRR 1235 1235 IRR \u0631\u06cc\u0627\u0644 1235 1235 IRR -\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235 1235 IRR P +\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235 1235 IRR CP test parse foreign currency full set pattern \u00a4\u00a4\u00a4 0.00;\u00a4\u00a4\u00a4 -# @@ -1249,10 +1247,10 @@ begin parse output outputCurrency breaks \u0631\u06cc\u0627\u0644 \u06F1\u06F2\u06F3\u06F5 1235 IRR IRR \u06F1\u06F2\u06F3\u06F5 1235 IRR -\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 \u06F1\u06F2\u06F3\u06F5 1235 IRR P +\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 \u06F1\u06F2\u06F3\u06F5 1235 IRR CP IRR 1235 1235 IRR \u0631\u06cc\u0627\u0644 1235 1235 IRR -\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235 1235 IRR P +\u0631\u06cc\u0627\u0644 \u0627\u06cc\u0631\u0627\u0646 1235 1235 IRR CP test parse currency with foreign symbols symbol english set pattern \u00a4 0.00;\u00a4 (#) @@ -1294,10 +1292,10 @@ begin parse currency output breaks $52.41 USD 52.41 USD52.41 USD 52.41 K -\u20ac52.41 USD fail P -EUR52.41 USD fail P -$52.41 EUR fail P -USD52.41 EUR fail P +\u20ac52.41 USD fail CP +EUR52.41 USD fail CP +$52.41 EUR fail CP +USD52.41 EUR fail CP \u20ac52.41 EUR 52.41 K EUR52.41 EUR 52.41 @@ -1307,11 +1305,11 @@ set locale en_US set lenient 0 begin parse output outputCurrency breaks -$53.45 53.45 USD P +$53.45 53.45 USD CP 53.45 USD 53.45 USD USD 53.45 fail USD 53.45USD fail USD -USD53.45 53.45 USD P +USD53.45 53.45 USD CP (7.92) USD -7.92 USD (7.92) EUR -7.92 EUR (7.926) USD -7.926 USD @@ -1329,9 +1327,9 @@ US Dollars 53.45 fail USD 53.45 US Dollars 53.45 USD US Dollar 53.45 fail USD 53.45 US Dollar 53.45 USD -US Dollars53.45 53.45 USD P +US Dollars53.45 53.45 USD CP 53.45US Dollars fail USD -US Dollar53.45 53.45 USD P +US Dollar53.45 53.45 USD CP US Dollat53.45 fail USD 53.45US Dollar fail USD US Dollars (53.45) fail USD @@ -1360,14 +1358,14 @@ begin pattern parse output breaks // K doesn't support this feature. 0 123 123 -0 123. fail CJK -0 1.23 fail CJK +0 123. fail JK +0 1.23 fail JK 0 -513 -513 -0 -513. fail CJK -0 -5.13 fail CJK +0 -513. fail JK +0 -5.13 fail JK 0.0 123 fail K -0.0 123. 123 C -0.0 1.23 1.23 C +0.0 123. 123 +0.0 1.23 1.23 0.0 -513 fail K 0.0 -513. -513 0.0 -5.13 -5.13 @@ -1397,17 +1395,17 @@ Aa1.23 0 1.23 AA1.23 1 fail // J and K do not support case-insensitive parsing for prefix/suffix. // J supports it for the exponent separator, but not K. -AA1.23 0 1.23 CJK +AA1.23 0 1.23 JK aa1.23 1 fail -aa1.23 0 1.23 CJK +aa1.23 0 1.23 JK Aa1.23E3 1 1230 Aa1.23E3 0 1230 -Aa1.23e3 1 1.23 CJ +Aa1.23e3 1 1.23 J Aa1.23e3 0 1230 K NaN 1 NaN K NaN 0 NaN K nan 1 fail -nan 0 NaN CJK +nan 0 NaN JK test parse infinity and scientific notation overflow set locale en @@ -1422,12 +1420,12 @@ NaN NaN K -1E-99999999999999 -0.0 1E2147483648 Inf K 1E2147483647 Inf K -1E2147483646 1E2147483646 +1E2147483646 1E2147483646 C 1E-2147483649 0 1E-2147483648 0 // P returns zero here 1E-2147483647 1E-2147483647 P -1E-2147483646 1E-2147483646 +1E-2147483646 1E-2147483646 C test format push limits set locale en @@ -1439,7 +1437,7 @@ maxFractionDigits format output breaks 100 987654321987654321 987654321987654321.00 C 100 987654321.987654321 987654321.987654321 C 100 9999999999999.9950000000001 9999999999999.9950000000001 C -2 9999999999999.9950000000001 10000000000000.00 C +2 9999999999999.9950000000001 10000000000000.00 2 9999999.99499999 9999999.99 // K doesn't support halfDown rounding mode? 2 9999999.995 9999999.99 K @@ -1491,13 +1489,13 @@ y gh56 -56 JK y g h56 -56 JK // S stops parsing after the 'i' for these and returns -56 // C stops before the 'i' and gets 56 -56ijk -56 CJK -56i jk -56 CJK -56ij k -56 CJK -56i‎j‎k -56 CJK -56ijk -56 CJK -56i j‎k -56 CJK -56‎i jk -56 CJK +56ijk -56 JK +56i jk -56 JK +56ij k -56 JK +56i‎j‎k -56 JK +56ijk -56 JK +56i j‎k -56 JK +56‎i jk -56 JK // S and C get 56 (accepts ' ' gs grouping); J and K get null 5 6 fail CP 5‎6 5 JK @@ -1546,7 +1544,7 @@ parse output breaks 55% 0.55 // J and K get null // P requires the symbol to be present and gets 55 -55 0.55 JKP +55 0.55 CJKP test trailing grouping separators in pattern // This test is for #13115 @@ -1565,8 +1563,8 @@ begin pattern format output breaks 0 -15 -15 0; -15 -15 -// C, J, and K still prepend a '-' even though the pattern says otherwise -0;0 -15 15 CJK +// J and K still prepend a '-' even though the pattern says otherwise +0;0 -15 15 JK test percentage multiplier parsing // This test is for #13129 @@ -1582,9 +1580,9 @@ set pattern 0 set signAlwaysShown 1 begin format output breaks -// C, J and K do not support this feature -42 +42 CJK -0 +0 CJK +// J and K do not support this feature +42 +42 JK +0 +0 JK -42 -42 test parse strict with plus sign @@ -1595,14 +1593,14 @@ begin lenient parse output breaks 1 42 42 1 -42 -42 -1 +42 42 CJK +1 +42 42 JK 1 0 0 -1 +0 0 CJK -0 42 fail CJK +1 +0 0 JK +0 42 fail JK 0 -42 -42 -0 +42 42 CJK -0 0 fail CJK -0 +0 0 CJK +0 +42 42 JK +0 0 fail JK +0 +0 0 JK