From 9cca22e331398812d10efd59212fffa6eb198dbe Mon Sep 17 00:00:00 2001 From: Alan Liu Date: Thu, 15 Apr 2004 06:20:42 +0000 Subject: [PATCH] ICU-2825 add support for formatting and parsing currency amounts X-SVN-Rev: 14978 --- icu4c/source/i18n/decimfmt.cpp | 148 ++++++++++++++---- icu4c/source/i18n/numfmt.cpp | 88 +++++++++-- icu4c/source/i18n/unicode/decimfmt.h | 83 ++++++++-- icu4c/source/i18n/unicode/numfmt.h | 75 ++++++--- icu4c/source/test/intltest/numfmtst.cpp | 55 ++++++- .../test/testdata/NumberFormatTestCases.txt | 13 ++ 6 files changed, 384 insertions(+), 78 deletions(-) diff --git a/icu4c/source/i18n/decimfmt.cpp b/icu4c/source/i18n/decimfmt.cpp index b31fb55efd7..c9a427c4b89 100644 --- a/icu4c/source/i18n/decimfmt.cpp +++ b/icu4c/source/i18n/decimfmt.cpp @@ -1187,8 +1187,39 @@ DecimalFormat::parse(const UnicodeString& text, void DecimalFormat::parse(const UnicodeString& text, Formattable& result, - ParsePosition& parsePosition) const -{ + ParsePosition& parsePosition) const { + parse(text, result, parsePosition, FALSE); +} + +Formattable& DecimalFormat::parseCurrency(const UnicodeString& text, + Formattable& result, + ParsePosition& pos) const { + parse(text, result, pos, TRUE); + return result; +} + +Formattable& DecimalFormat::parseCurrency(const UnicodeString& text, + Formattable& result, + UErrorCode& status) const { + return NumberFormat::parseCurrency(text, result, status); +} + +/** + * Parses the given text as either a number or a currency amount. + * @param text the string to parse + * @param result output parameter for the result + * @param parsePosition input-output position; on input, the + * position within text to match; must have 0 <= pos.getIndex() < + * text.length(); on output, the position after the last matched + * character. If the parse fails, the position in unchanged upon + * output. + * @param parseCurrency if true, a currency amount is parsed; + * otherwise a Number is parsed + */ +void DecimalFormat::parse(const UnicodeString& text, + Formattable& result, + ParsePosition& parsePosition, + UBool parseCurrency) const { int32_t backup; int32_t i = backup = parsePosition.getIndex(); @@ -1219,13 +1250,19 @@ DecimalFormat::parse(const UnicodeString& text, // status is used to record whether a number is infinite. UBool status[fgStatusLength]; + UChar curbuf[4]; + UChar* currency = parseCurrency ? curbuf : NULL; DigitList digits; - if (!subparse(text, parsePosition, digits, status)) { + if (!subparse(text, parsePosition, digits, status, currency)) { parsePosition.setIndex(backup); return; } + if (parseCurrency) { + result.setCurrency(curbuf); + } + // Handle infinity if (status[fgStatusInfinite]) { double inf = uprv_getInfinity(); @@ -1283,21 +1320,27 @@ DecimalFormat::parse(const UnicodeString& text, This is an old implimentation that was preparing for 64-bit numbers in ICU. It is very slow, and 64-bit numbers are not ANSI-C compatible. This code is here if we change our minds. + +^^^ what is this referring to? remove? ^^^ [alan] */ + /** * Parse the given text into a number. The text is parsed beginning at * parsePosition, until an unparseable character is seen. - * @param text The string to parse. + * @param text the string to parse. * @param parsePosition The position at which to being parsing. Upon - * return, the first unparseable character. - * @param digits The DigitList to set to the parsed value. - * @param isExponent If true, parse an exponent. This means no - * infinite values and integer only. By default it's really false. - * @param status Upon return contains boolean status flags indicating + * return, the first unparsed character. + * @param digits the DigitList to set to the parsed value. + * @param status output param containing boolean status flags indicating * whether the value was infinite and whether it was positive. + * @param currency return value for parsed currency, for generic + * currency parsing mode, or NULL for normal parsing. In generic + * currency parsing mode, any currency is parsed, not just the + * currency that this formatter is set to. */ UBool DecimalFormat::subparse(const UnicodeString& text, ParsePosition& parsePosition, - DigitList& digits, UBool* status) const + DigitList& digits, UBool* status, + UChar* currency) const { int32_t position = parsePosition.getIndex(); int32_t oldStart = position; @@ -1308,8 +1351,8 @@ UBool DecimalFormat::subparse(const UnicodeString& text, ParsePosition& parsePos } // Match positive and negative prefixes; prefer longest match. - int32_t posMatch = compareAffix(text, position, FALSE, TRUE); - int32_t negMatch = compareAffix(text, position, TRUE, TRUE); + int32_t posMatch = compareAffix(text, position, FALSE, TRUE, currency); + int32_t negMatch = compareAffix(text, position, TRUE, TRUE, currency); if (posMatch >= 0 && negMatch >= 0) { if (posMatch > negMatch) { negMatch = -1; @@ -1524,10 +1567,10 @@ UBool DecimalFormat::subparse(const UnicodeString& text, ParsePosition& parsePos // Match positive and negative suffixes; prefer longest match. if (posMatch >= 0) { - posMatch = compareAffix(text, position, FALSE, FALSE); + posMatch = compareAffix(text, position, FALSE, FALSE, currency); } if (negMatch >= 0) { - negMatch = compareAffix(text, position, TRUE, FALSE); + negMatch = compareAffix(text, position, TRUE, FALSE, currency); } if (posMatch >= 0 && negMatch >= 0) { if (posMatch > negMatch) { @@ -1585,19 +1628,24 @@ int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position) * @param pos offset into input at which to begin matching * @param isNegative * @param isPrefix + * @param currency return value for parsed currency, for generic + * currency parsing mode, or null for normal parsing. In generic + * currency parsing mode, any currency is parsed, not just the + * currency that this formatter is set to. * @return length of input that matches, or -1 if match failure */ int32_t DecimalFormat::compareAffix(const UnicodeString& text, int32_t pos, UBool isNegative, - UBool isPrefix) const { - if (fCurrencyChoice != NULL) { + UBool isPrefix, + UChar* currency) const { + if (fCurrencyChoice != NULL || currency != NULL) { if (isPrefix) { return compareComplexAffix(isNegative ? *fNegPrefixPattern : *fPosPrefixPattern, - text, pos); + text, pos, currency); } else { return compareComplexAffix(isNegative ? *fNegSuffixPattern : *fPosSuffixPattern, - text, pos); + text, pos, currency); } } @@ -1709,13 +1757,18 @@ int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) { * @param affixPat pattern string * @param input input text * @param pos offset into input at which to begin matching + * @param currency return value for parsed currency, for generic + * currency parsing mode, or null for normal parsing. In generic + * currency parsing mode, any currency is parsed, not just the + * currency that this formatter is set to. * @return length of input that matches, or -1 if match failure */ int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat, const UnicodeString& text, - int32_t pos) const { - U_ASSERT(fCurrencyChoice != NULL); - U_ASSERT(*getCurrency() != 0); + int32_t pos, + UChar* currency) const { + U_ASSERT(currency != NULL || + (fCurrencyChoice != NULL && *getCurrency() != 0)); for (int32_t i=0; i= 0; ) { UChar32 c = affixPat.char32At(i); @@ -1730,16 +1783,44 @@ int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat, switch (c) { case kCurrencySign: { + // If currency != null, then perform generic currency matching. + // Otherwise, do currency choice parsing. UBool intl = igetLocale().getName(); + ec = U_ZERO_ERROR; + } + // Delegate parse of display name => ISO code to Currency ParsePosition ppos(pos); - Formattable result; - fCurrencyChoice->parse(text, result, ppos); - pos = (ppos.getIndex() == pos) ? -1 : ppos.getIndex(); + UChar curr[4]; + uprv_parseCurrency(loc, text, ppos, curr, ec); + + // If parse succeeds, populate currency[0] + if (U_SUCCESS(ec) && ppos.getIndex() != pos) { + u_strcpy(currency, curr); + pos = ppos.getIndex(); + } else { + pos = -1; + } + } else { + if (intl) { + ++i; + pos = match(text, pos, getCurrency()); + } else { + ParsePosition ppos(pos); + Formattable result; + fCurrencyChoice->parse(text, result, ppos); + pos = (ppos.getIndex() == pos) ? -1 : ppos.getIndex(); + } } continue; } @@ -3607,6 +3688,17 @@ void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) { } } +void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const { + const UChar* c = getCurrency(); + if (*c == 0) { + const UnicodeString &intl = + fSymbols->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol); + c = intl.getBuffer(); // ok for intl to go out of scope + } + u_strncpy(result, c, 3); + result[3] = 0; +} + /** * Return the number of fraction digits to display, or the total * number of digits for significant digit formats and exponential diff --git a/icu4c/source/i18n/numfmt.cpp b/icu4c/source/i18n/numfmt.cpp index c5673cfbb0b..fe1a5523448 100644 --- a/icu4c/source/i18n/numfmt.cpp +++ b/icu4c/source/i18n/numfmt.cpp @@ -32,6 +32,7 @@ #include "unicode/dcfmtsym.h" #include "unicode/decimfmt.h" #include "unicode/ustring.h" +#include "unicode/ucurr.h" #include "uhash.h" #include "iculserv.h" #include "ucln_in.h" @@ -220,20 +221,41 @@ NumberFormat::format(const Formattable& obj, { if (U_FAILURE(status)) return appendTo; - if (obj.getType() == Formattable::kDouble) { - return format(obj.getDouble(), appendTo, pos); + NumberFormat* nonconst = (NumberFormat*) this; + + UChar save[4]; + UBool setCurr = FALSE; + const UChar *curr = obj.getCurrency(); // most commonly curr==NULL + if (curr != NULL) { + // getCurrency() returns a pointer to internal storage, so we + // copy it to retain it across the call to setCurrency(). + u_strcpy(save, getCurrency()); + setCurr = (u_strcmp(curr, save) != 0); + if (setCurr) { + nonconst->setCurrency(curr, status); + } } - else if (obj.getType() == Formattable::kLong) { - return format(obj.getLong(), appendTo, pos); - } - else if (obj.getType() == Formattable::kInt64) { - return format(obj.getInt64(), appendTo, pos); - } - // can't try to format a non-numeric object - else { + + switch (obj.getType()) { + case Formattable::kDouble: + format(obj.getDouble(), appendTo, pos); + break; + case Formattable::kLong: + format(obj.getLong(), appendTo, pos); + break; + case Formattable::kInt64: + format(obj.getInt64(), appendTo, pos); + break; + default: status = U_INVALID_FORMAT_ERROR; - return appendTo; + break; } + + if (setCurr) { + UErrorCode ok = U_ZERO_ERROR; + nonconst->setCurrency(save, ok); // always restore currency + } + return appendTo; } // ------------------------------------- @@ -309,6 +331,36 @@ NumberFormat::parse(const UnicodeString& text, } } +Formattable& NumberFormat::parseCurrency(const UnicodeString& text, + Formattable& result, + ParsePosition& pos) const { + // Default implementation only -- subclasses should override + int32_t start = pos.getIndex(); + parse(text, result, pos); + if (pos.getIndex() != start) { + UChar curr[4]; + UErrorCode ec = U_ZERO_ERROR; + getEffectiveCurrency(curr, ec); + if (U_SUCCESS(ec)) { + result.setCurrency(curr); + } + } + return result; +} + +Formattable& NumberFormat::parseCurrency(const UnicodeString& text, + Formattable& result, + UErrorCode& ec) const { + if (U_SUCCESS(ec)) { + ParsePosition pos(0); + parseCurrency(text, result, pos); + if (pos.getIndex() == 0) { + ec = U_INVALID_FORMAT_ERROR; + } + } + return result; +} + // ------------------------------------- // Sets to only parse integers. @@ -716,6 +768,20 @@ const UChar* NumberFormat::getCurrency() const { return fCurrency; } +void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const { + const UChar* c = getCurrency(); + if (*c != 0) { + u_strncpy(result, c, 3); + result[3] = 0; + } else { + const char* loc = getLocaleID(ULOC_VALID_LOCALE, ec); + if (loc == NULL) { + loc = uloc_getDefault(); + } + ucurr_forLocale(loc, result, 4, &ec); + } +} + // ------------------------------------- // Creates the NumberFormat instance of the specified style (number, currency, // or percent) for the desired locale. diff --git a/icu4c/source/i18n/unicode/decimfmt.h b/icu4c/source/i18n/unicode/decimfmt.h index bd4a15ed7b9..aaa38844284 100644 --- a/icu4c/source/i18n/unicode/decimfmt.h +++ b/icu4c/source/i18n/unicode/decimfmt.h @@ -868,6 +868,52 @@ public: Formattable& result, UErrorCode& status) const; + /** + * Parses text from the given string as a currency amount. Unlike + * the parse() method, this method will attempt to parse a generic + * currency name, searching for a match of this object's locale's + * currency display names, or for a 3-letter ISO currency code. + * This method will fail if this format is not a currency format, + * that is, if it does not contain the currency pattern symbol + * (U+00A4) in its prefix or suffix. + * + * @param text the string to parse + * @param result output parameter to receive result. This will have + * its currency set to the parsed ISO currency code. + * @param pos input-output position; on input, the position within + * text to match; must have 0 <= pos.getIndex() < text.length(); + * on output, the position after the last matched character. If + * the parse fails, the position in unchanged upon output. + * @return a reference to result + * @draft ICU 3.0 + */ + virtual Formattable& parseCurrency(const UnicodeString& text, + Formattable& result, + ParsePosition& pos) const; + + // Redeclare here, otherwise function will be hidden + /** + * Parses text from the beginning of the given string as a + * currency amount. The method might not use the entire text of + * the given string. Unlike the parse() method, this method will + * attempt to parse a generic currency name, searching for a match + * of this object's locale's currency display names, or for a + * 3-letter ISO currency code. This method will fail if this + * format is not a currency format, that is, if it does not + * contain the currency pattern symbol (U+00A4) in its prefix or + * suffix. + * + * @param text the string to parse + * @param result output parameter to receive result. This will have + * its currency set to the parsed ISO currency code. + * @param status input-output error code + * @return a reference to result + * @draft ICU 3.0 + */ + Formattable& parseCurrency(const UnicodeString& text, + Formattable& result, + UErrorCode& status) const; + /** * Returns the decimal format symbols, which is generally not changed * by the programmer or user. @@ -1621,32 +1667,27 @@ private: DigitList& digits, UBool isInteger) const; + void parse(const UnicodeString& text, + Formattable& result, + ParsePosition& pos, + UBool parseCurrency) const; + enum { fgStatusInfinite, fgStatusLength // Leave last in list. } StatusFlags; - /** - * Parse the given text into a number. The text is parsed beginning at - * parsePosition, until an unparseable character is seen. - * @param text The string to parse. - * @param parsePosition The position at which to being parsing. Upon - * return, the first unparseable character. - * @param digits The DigitList to set to the parsed value. - * @param isExponent If true, parse an exponent. This means no - * infinite values and integer only. - * @param status Upon return contains boolean status flags indicating - * whether the value was infinite and whether it was positive. - */ UBool subparse(const UnicodeString& text, ParsePosition& parsePosition, - DigitList& digits, UBool* status) const; + DigitList& digits, UBool* status, + UChar* currency) const; int32_t skipPadding(const UnicodeString& text, int32_t position) const; int32_t compareAffix(const UnicodeString& input, int32_t pos, UBool isNegative, - UBool isPrefix) const; + UBool isPrefix, + UChar* currency) const; static int32_t compareSimpleAffix(const UnicodeString& affix, const UnicodeString& input, @@ -1658,7 +1699,8 @@ private: int32_t compareComplexAffix(const UnicodeString& affixPat, const UnicodeString& input, - int32_t pos) const; + int32_t pos, + UChar* currency) const; static int32_t match(const UnicodeString& text, int32_t pos, UChar32 ch); @@ -1756,6 +1798,17 @@ private: EPadPosition fPadPosition; protected: + + /** + * Returns the currency in effect for this formatter. Subclasses + * should override this method as needed. Unlike getCurrency(), + * this method should never return "". + * @result output parameter for null-terminated result, which must + * have a capacity of at least 4 + * @internal + */ + virtual void getEffectiveCurrency(UChar* result, UErrorCode& ec) const; + /** number of integer digits * @stable ICU 2.4 */ diff --git a/icu4c/source/i18n/unicode/numfmt.h b/icu4c/source/i18n/unicode/numfmt.h index 28bef3642b4..decd564884a 100644 --- a/icu4c/source/i18n/unicode/numfmt.h +++ b/icu4c/source/i18n/unicode/numfmt.h @@ -1,5 +1,5 @@ /* -* Copyright (C) {1997-2003}, International Business Machines Corporation and others. All Rights Reserved. +* Copyright (C) {1997-2004}, International Business Machines Corporation and others. All Rights Reserved. ******************************************************************************** * * File NUMFMT.H @@ -201,8 +201,8 @@ public: *

* Before calling, set parse_pos.index to the offset you want to * start parsing at in the source. After calling, parse_pos.index - * is the end of the text you parsed. If error occurs, index is - * unchanged. + * indicates the position after the successfully parsed text. If + * an error occurs, parse_pos.index is unchanged. *

* When parsing, leading whitespace is discarded (with successful * parse), while trailing whitespace is left as is. @@ -370,6 +370,51 @@ public: Formattable& result, UErrorCode& status) const; + /** + * Parses text from the given string as a currency amount. Unlike + * the parse() method, this method will attempt to parse a generic + * currency name, searching for a match of this object's locale's + * currency display names, or for a 3-letter ISO currency code. + * This method will fail if this format is not a currency format, + * that is, if it does not contain the currency pattern symbol + * (U+00A4) in its prefix or suffix. + * + * @param text the string to parse + * @param result output parameter to receive result. This will have + * its currency set to the parsed ISO currency code. + * @param pos input-output position; on input, the position within + * text to match; must have 0 <= pos.getIndex() < text.length(); + * on output, the position after the last matched character. If + * the parse fails, the position in unchanged upon output. + * @return a reference to result + * @draft ICU 3.0 + */ + virtual Formattable& parseCurrency(const UnicodeString& text, + Formattable& result, + ParsePosition& pos) const; + + /** + * Parses text from the beginning of the given string as a + * currency amount. The method might not use the entire text of + * the given string. Unlike the parse() method, this method will + * attempt to parse a generic currency name, searching for a match + * of this object's locale's currency display names, or for a + * 3-letter ISO currency code. This method will fail if this + * format is not a currency format, that is, if it does not + * contain the currency pattern symbol (U+00A4) in its prefix or + * suffix. + * + * @param text the string to parse + * @param result output parameter to receive result. This will have + * its currency set to the parsed ISO currency code. + * @param status input-output error code + * @return a reference to result + * @draft ICU 3.0 + */ + Formattable& parseCurrency(const UnicodeString& text, + Formattable& result, + UErrorCode& status) const; + /** * Return true if this format will parse numbers as integers * only. For example in the English locale, with ParseIntegerOnly @@ -658,18 +703,14 @@ protected: NumberFormat& operator=(const NumberFormat&); /** - * Sets the minimum integer digits count directly, with no range - * pinning. For use by subclasses. + * Returns the currency in effect for this formatter. Subclasses + * should override this method as needed. Unlike getCurrency(), + * this method should never return "". + * @result output parameter for null-terminated result, which must + * have a capacity of at least 4 * @internal */ - inline void internalSetMinimumIntegerDigits(int32_t n); - - /** - * Sets the maximum integer digits count directly, with no range - * pinning. For use by subclasses. - * @internal - */ - inline void internalSetMaximumIntegerDigits(int32_t n); + virtual void getEffectiveCurrency(UChar* result, UErrorCode& ec) const; private: static const int32_t fgMaxIntegerDigits; @@ -823,14 +864,6 @@ NumberFormat::format(const Formattable& obj, return Format::format(obj, appendTo, status); } -inline void NumberFormat::internalSetMinimumIntegerDigits(int32_t n) { - fMinIntegerDigits = n; -} - -inline void NumberFormat::internalSetMaximumIntegerDigits(int32_t n) { - fMaxIntegerDigits = n; -} - U_NAMESPACE_END #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/test/intltest/numfmtst.cpp b/icu4c/source/test/intltest/numfmtst.cpp index 5f43f7cf7f0..8bdbb5b8c66 100644 --- a/icu4c/source/test/intltest/numfmtst.cpp +++ b/icu4c/source/test/intltest/numfmtst.cpp @@ -1534,8 +1534,9 @@ static const char* KEYWORDS[] = { /*3*/ "fp:", // /*4*/ "rt:", // <(exp.) number> <(exp.) string> /*5*/ "p:", // - /*6*/ "perr:", // + /*6*/ "perr:", // /*7*/ "pat:", // + /*8*/ "fpc:", // 0 }; @@ -1554,6 +1555,23 @@ static int32_t keywordIndex(const UnicodeString& tok) { return -1; } +/** + * Parse a CurrencyAmount using the given NumberFormat, with + * the 'delim' character separating the number and the currency. + */ +static void parseCurrencyAmount(const UnicodeString& str, + const NumberFormat& fmt, + UChar delim, + Formattable& result, + UErrorCode& ec) { + UnicodeString num, cur; + int32_t i = str.indexOf(delim); + str.extractBetween(0, i, num); + str.extractBetween(i+1, INT32_MAX, cur); + fmt.parse(num, result, ec); + result.setCurrency(cur.getTerminatedBuffer()); +} + void NumberFormatTest::TestCases() { UErrorCode ec = U_ZERO_ERROR; TextFile reader("NumberFormatTestCases.txt", "UTF8", ec); @@ -1591,17 +1609,18 @@ void NumberFormatTest::TestCases() { case 3: // fp: case 4: // rt: case 5: // p: + case 8: // fpc: if (!tokens.next(tok, ec)) goto error; if (tok != "-") { pat = tok; delete fmt; fmt = new DecimalFormat(pat, new DecimalFormatSymbols(loc, ec), ec); if (U_FAILURE(ec)) { - errln("FAIL: " + where + "Pattern \"" + pat + "\""); + errln("FAIL: " + where + "Pattern \"" + pat + "\": " + u_errorName(ec)); ec = U_ZERO_ERROR; if (!tokens.next(tok, ec)) goto error; if (!tokens.next(tok, ec)) goto error; - if (cmd == 3) { + if (cmd == 3 || cmd == 8) { if (!tokens.next(tok, ec)) goto error; } continue; @@ -1633,6 +1652,36 @@ void NumberFormatTest::TestCases() { n, m); } } + // fpc: + else if (cmd == 8) { + UnicodeString currAmt; + if (!tokens.next(currAmt, ec)) goto error; + if (!tokens.next(str, ec)) goto error; + Formattable n; + parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec); + if (assertSuccess("parseCurrencyAmount", ec)) { + UChar save[4]; + u_strcpy(save, fmt->getCurrency()); + assertEquals(where + "\"" + pat + "\".format(" + currAmt + ")", + str, fmt->format(n, out.remove(), ec)); + assertSuccess("format", ec); + if (u_strcmp(save, fmt->getCurrency()) != 0) { + errln((UnicodeString)"FAIL: " + where + + "NumberFormat.getCurrency() => " + fmt->getCurrency() + + ", expected " + save); + } + } + if (!tokens.next(currAmt, ec)) goto error; + parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec); + if (assertSuccess("parseCurrencyAmount", ec)) { + Formattable m; + fmt->parseCurrency(str, m, ec); + if (assertSuccess("parseCurrency", ec)) { + assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")", + n, m); + } + } + } // p: else { UnicodeString expstr; diff --git a/icu4c/source/test/testdata/NumberFormatTestCases.txt b/icu4c/source/test/testdata/NumberFormatTestCases.txt index 806d506c9e2..1886c3e3769 100644 --- a/icu4c/source/test/testdata/NumberFormatTestCases.txt +++ b/icu4c/source/test/testdata/NumberFormatTestCases.txt @@ -70,3 +70,16 @@ pat: "@@0" err # either @ or 0, not both # NumberRegression/Test4140009 rt: "" 123.456 "123.456" rt: "" -123.456 "-123.456" + +# Currency +fpc: "\u00A4 0.00" 1234.56/USD "$ 1234.56" 1234.56/USD +fpc: - 1234.56/JPY "\u00A5 1235" 1235/JPY +# ISO codes that overlap display names (QQQ vs. Q) +fpc: - 123/QQQ "QQQ 123.00" 123/QQQ # QQQ is fake +fpc: - 123/GTQ "Q 123.00" 123/GTQ +# ChoiceFormat-based display names +fpc: - 1/INR "Re. 1.00" 1/INR +fpc: - 2/INR "Rs. 2.00" 2/INR +# Display names with shared prefix (YDD vs. Y) +fpc: - 100/YDD "YDD 100.00" 100/YDD +fpc: - 100/CNY "Y 100.00" 100/CNY