]> granicus.if.org Git - icu/commitdiff
ICU-13634 Fixing more assorted currency parsing issues.
authorShane Carr <shane@unicode.org>
Wed, 11 Apr 2018 02:18:13 +0000 (02:18 +0000)
committerShane Carr <shane@unicode.org>
Wed, 11 Apr 2018 02:18:13 +0000 (02:18 +0000)
X-SVN-Rev: 41214

icu4c/source/i18n/number_currencysymbols.cpp
icu4c/source/i18n/numparse_currency.cpp
icu4c/source/test/intltest/numfmtst.cpp
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/CombinedCurrencyMatcher.java
icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberformattestspecification.txt
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatDataDrivenTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java

index 8f05da78c4ee1995445b29519b2963c20ffd23d5..51f37076e7c9761f7509bb560e1fbc3936dab2ae 100644 (file)
@@ -52,17 +52,23 @@ UnicodeString CurrencySymbols::getCurrencySymbol(UErrorCode& status) const {
 }
 
 UnicodeString CurrencySymbols::loadSymbol(UCurrNameStyle selector, UErrorCode& status) const {
+    const char16_t* isoCode = fCurrency.getISOCurrency();
     UBool ignoredIsChoiceFormatFillIn = FALSE;
     int32_t symbolLen = 0;
     const char16_t* symbol = ucurr_getName(
-            fCurrency.getISOCurrency(),
+            isoCode,
             fLocaleName.data(),
             selector,
             &ignoredIsChoiceFormatFillIn,
             &symbolLen,
             &status);
-    // Readonly-aliasing char16_t* constructor, which points to a resource bundle:
-    return UnicodeString(TRUE, symbol, symbolLen);
+    // If given an unknown currency, ucurr_getName returns the input string, which we can't alias safely!
+    // Otherwise, symbol points to a resource bundle, and we can use readonly-aliasing constructor.
+    if (symbol == isoCode) {
+        return UnicodeString(isoCode, 3);
+    } else {
+        return UnicodeString(TRUE, symbol, symbolLen);
+    }
 }
 
 UnicodeString CurrencySymbols::getIntlCurrencySymbol(UErrorCode&) const {
@@ -75,17 +81,23 @@ UnicodeString CurrencySymbols::getIntlCurrencySymbol(UErrorCode&) const {
 }
 
 UnicodeString CurrencySymbols::getPluralName(StandardPlural::Form plural, UErrorCode& status) const {
+    const char16_t* isoCode = fCurrency.getISOCurrency();
     UBool isChoiceFormat = FALSE;
     int32_t symbolLen = 0;
     const char16_t* symbol = ucurr_getPluralName(
-            fCurrency.getISOCurrency(),
+            isoCode,
             fLocaleName.data(),
             &isChoiceFormat,
             StandardPlural::getKeyword(plural),
             &symbolLen,
             &status);
-    // Readonly-aliasing char16_t* constructor, which points to a resource bundle:
-    return UnicodeString(TRUE, symbol, symbolLen);
+    // If given an unknown currency, ucurr_getName returns the input string, which we can't alias safely!
+    // Otherwise, symbol points to a resource bundle, and we can use readonly-aliasing constructor.
+    if (symbol == isoCode) {
+        return UnicodeString(isoCode, 3);
+    } else {
+        return UnicodeString(TRUE, symbol, symbolLen);
+    }
 }
 
 
index 5c14fd7429e4dd3b0340f0694566925dd957a154..084837596289276239bffa86842296cfb9ff230f 100644 (file)
@@ -81,7 +81,7 @@ bool CombinedCurrencyMatcher::match(StringSegment& segment, ParsedNumber& result
 bool CombinedCurrencyMatcher::matchCurrency(StringSegment& segment, ParsedNumber& result,
                                             UErrorCode& status) const {
 
-    int32_t overlap1 = segment.getCommonPrefixLength(fCurrency1);
+    int32_t overlap1 = segment.getCaseSensitivePrefixLength(fCurrency1);
     if (overlap1 == fCurrency1.length()) {
         utils::copyCurrencyCode(result.currencyCode, fCurrencyCode);
         segment.adjustOffset(overlap1);
@@ -89,7 +89,7 @@ bool CombinedCurrencyMatcher::matchCurrency(StringSegment& segment, ParsedNumber
         return segment.length() == 0;
     }
 
-    int32_t overlap2 = segment.getCommonPrefixLength(fCurrency2);
+    int32_t overlap2 = segment.getCaseSensitivePrefixLength(fCurrency2);
     if (overlap2 == fCurrency2.length()) {
         utils::copyCurrencyCode(result.currencyCode, fCurrencyCode);
         segment.adjustOffset(overlap2);
index bf070fa75ac3750bbd4c76a6d26ab9cd75eecba2..cf9bd3bc8a4b0c95014185dd2df92f528ba1f6e9 100644 (file)
@@ -4082,24 +4082,24 @@ NumberFormatTest::TestCurrencyParsing() {
         // format result using CURRENCYSTYLE,
         // format result using ISOCURRENCYSTYLE,
         // format result using PLURALCURRENCYSTYLE,
-        {"en_US", "1", "USD", "$1.00", "USD1.00", "1.00 US dollar"},
+        {"en_US", "1", "USD", "$1.00", "USD\\u00A01.00", "1.00 US dollar"},
         {"pa_IN", "1", "USD", "US$\\u00A01.00", "USD\\u00A01.00", "1.00 \\u0a2f\\u0a42.\\u0a10\\u0a38. \\u0a21\\u0a3e\\u0a32\\u0a30"},
         {"es_AR", "1", "USD", "US$\\u00A01,00", "USD\\u00A01,00", "1,00 d\\u00f3lar estadounidense"},
         {"ar_EG", "1", "USD", "\\u0661\\u066b\\u0660\\u0660\\u00a0US$", "\\u0661\\u066b\\u0660\\u0660\\u00a0USD", "\\u0661\\u066b\\u0660\\u0660 \\u062f\\u0648\\u0644\\u0627\\u0631 \\u0623\\u0645\\u0631\\u064a\\u0643\\u064a"},
         {"fa_CA", "1", "USD", "\\u200e$\\u06f1\\u066b\\u06f0\\u06f0", "\\u200eUSD\\u06f1\\u066b\\u06f0\\u06f0", "\\u06f1\\u066b\\u06f0\\u06f0 \\u062f\\u0644\\u0627\\u0631 \\u0627\\u0645\\u0631\\u06cc\\u06a9\\u0627"},
         {"he_IL", "1", "USD", "\\u200f1.00\\u00a0$", "\\u200f1.00\\u00a0USD", "1.00 \\u05d3\\u05d5\\u05dc\\u05e8 \\u05d0\\u05de\\u05e8\\u05d9\\u05e7\\u05d0\\u05d9"},
         {"hr_HR", "1", "USD", "1,00\\u00a0USD", "1,00\\u00a0USD", "1,00 Ameri\\u010dki dolar"},
-        {"id_ID", "1", "USD", "US$1,00", "USD1,00", "1,00 Dolar Amerika Serikat"},
+        {"id_ID", "1", "USD", "US$\\u00A01,00", "USD\\u00A01,00", "1,00 Dolar Amerika Serikat"},
         {"it_IT", "1", "USD", "1,00\\u00a0USD", "1,00\\u00a0USD", "1,00 Dollaro Statunitense"},
-        {"ko_KR", "1", "USD", "US$1.00", "USD1.00", "1.00 \\ubbf8\\uad6d \\ub2ec\\ub7ec"},
-        {"ja_JP", "1", "USD", "$1.00", "USD1.00", "1.00\\u7c73\\u30c9\\u30eb"},
-        {"zh_CN", "1", "CNY", "\\uFFE51.00", "CNY01.00", "1.00\\u4EBA\\u6C11\\u5E01"},
-        {"zh_TW", "1", "CNY", "CN\\u00A51.00", "CNY1.00", "1.00 \\u4eba\\u6c11\\u5e63"},
-        {"zh_Hant", "1", "CNY", "CN\\u00A51.00", "CNY1.00", "1.00 \\u4eba\\u6c11\\u5e63"},
-        {"zh_Hant", "1", "JPY", "\\u00A51.00", "JPY1.00", "1.00 \\u65e5\\u5713"},
-        {"ja_JP", "1", "JPY", "\\uFFE51.00", "JPY1.00", "1.00\\u65e5\\u672c\\u5186"},
-        {"ja_JP", "1", "JPY", "\\u00A51.00", "JPY1.00", "1.00\\u65e5\\u672c\\u5186"},
-        {"ru_RU", "1", "RUB", "1,00\\u00A0\\u20BD", "1,00\\u00A0RUB", "1,00 \\u0420\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0439 \\u0440\\u0443\\u0431\\u043B\\u044C"}
+        {"ko_KR", "1", "USD", "US$\\u00A01.00", "USD\\u00A01.00", "1.00 \\ubbf8\\uad6d \\ub2ec\\ub7ec"},
+        {"ja_JP", "1", "USD", "$1.00", "USD\\u00A01.00", "1.00\\u00A0\\u7c73\\u30c9\\u30eb"},
+        {"zh_CN", "1", "CNY", "\\uFFE51.00", "CNY\\u00A001.00", "1.00\\u00A0\\u4EBA\\u6C11\\u5E01"},
+        {"zh_TW", "1", "CNY", "CN\\u00A51.00", "CNY\\u00A01.00", "1.00 \\u4eba\\u6c11\\u5e63"},
+        {"zh_Hant", "1", "CNY", "CN\\u00A51.00", "CNY\\u00A01.00", "1.00 \\u4eba\\u6c11\\u5e63"},
+        {"zh_Hant", "1", "JPY", "\\u00A51.00", "JPY\\u00A01.00", "1.00 \\u65e5\\u5713"},
+        {"ja_JP", "1", "JPY", "\\uFFE51.00", "JPY\\u00A01.00", "1.00\\u00A0\\u65e5\\u672c\\u5186"},
+        {"ja_JP", "1", "JPY", "\\u00A51.00", "JPY\\u00A01.00", "1.00\\u00A0\\u65e5\\u672c\\u5186"},
+        {"ru_RU", "1", "RUB", "1,00\\u00A0\\u00A0\\u20BD", "1,00\\u00A0\\u00A0RUB", "1,00 \\u0420\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0439 \\u0440\\u0443\\u0431\\u043B\\u044C"}
     };
     static const UNumberFormatStyle currencyStyles[] = {
         UNUM_CURRENCY,
@@ -4158,7 +4158,9 @@ for (;;) {
         }
         */
         // test parsing, and test parsing for all currency formats.
-        for (int j = 3; j < 6; ++j) {
+        // NOTE: ICU 62 requires that the currency format match the pattern in strict mode.
+        //for (int j = 3; j < 6; ++j) {
+        for (int j = 3 + kIndex; j <= 3 + kIndex; j++) {
             // DATA[i][3] is the currency format result using
             // CURRENCYSTYLE formatter.
             // DATA[i][4] is the currency format result using
@@ -6744,6 +6746,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() {
       UnicodeString formatted = ctou(DATA[i]);
       UErrorCode status = U_ZERO_ERROR;
       NumberFormat* numFmt = NumberFormat::createInstance(locale, UNUM_CURRENCY, status);
+      numFmt->setLenient(TRUE); // ICU 62 PATCH
       if (numFmt != NULL && U_SUCCESS(status)) {
           ParsePosition parsePos;
           LocalPointer<CurrencyAmount> currAmt(numFmt->parseCurrency(formatted, parsePos));
index c1d14189b68e98baeb6c2ce4491bc1ebba599713..ee303092b3320ea9e4035bfa677d3227f16d9ac0 100644 (file)
@@ -109,7 +109,7 @@ public class CombinedCurrencyMatcher implements NumberParseMatcher {
 
     /** Matches the currency string without concern for currency spacing. */
     private boolean matchCurrency(StringSegment segment, ParsedNumber result) {
-        int overlap1 = segment.getCommonPrefixLength(currency1);
+        int overlap1 = segment.getCaseSensitivePrefixLength(currency1);
         if (overlap1 == currency1.length()) {
             result.currencyCode = isoCode;
             segment.adjustOffset(overlap1);
@@ -117,7 +117,7 @@ public class CombinedCurrencyMatcher implements NumberParseMatcher {
             return segment.length() == 0;
         }
 
-        int overlap2 = segment.getCommonPrefixLength(currency2);
+        int overlap2 = segment.getCaseSensitivePrefixLength(currency2);
         if (overlap2 == currency2.length()) {
             result.currencyCode = isoCode;
             segment.adjustOffset(overlap2);
index b38a420f2c7d142a54b113a0266c16b61bc6005f..35731ff8b7b3194173d18d548ba4c90455bdf8c4 100644 (file)
@@ -1023,7 +1023,7 @@ begin
 parse  output  outputCurrency  breaks
 53.45  fail    GBP
 £53.45        53.45   GBP
-$53.45 fail    USD     J
+$53.45 fail    USD     JP
 53.45 USD      53.45   USD
 53.45 GBP      53.45   GBP
 USD 53.45      53.45   USD     J
@@ -1041,7 +1041,7 @@ USD(7.92) -7.92   USD     CJ
 (8) USD        -8      USD
 -8 USD -8      USD     C
 67 USD 67      USD
-53.45$ fail    USD
+53.45$ fail    USD     P
 US Dollars 53.45       53.45   USD     J
 53.45 US Dollars       53.45   USD
 US Dollar 53.45        53.45   USD     J
@@ -1070,7 +1070,7 @@ begin
 parse  output  outputCurrency  breaks
 53.45  fail    GBP
 £53.45        53.45   GBP
-$53.45 fail    USD     J
+$53.45 fail    USD     JP
 53.45 USD      53.45   USD
 53.45 GBP      53.45   GBP
 USD 53.45      53.45   USD     J
@@ -1084,7 +1084,7 @@ USD -7.926        -7.926  USD     CJ
 USD-7.92       -7.92   USD     CJ
 -8 USD -8      USD
 67 USD 67      USD
-53.45$ fail    USD
+53.45$ fail    USD     P
 US Dollars 53.45       53.45   USD     J
 53.45 US Dollars       53.45   USD
 US Dollar 53.45        53.45   USD     J
@@ -1104,7 +1104,7 @@ parse     output  outputCurrency  breaks
 // J throws a NullPointerException on the first case
 53.45  fail    GBP
 £53.45        53.45   GBP
-$53.45 fail    USD     J
+$53.45 fail    USD     JP
 53.45 USD      53.45   USD
 53.45 GBP      53.45   GBP
 USD 53.45      53.45   USD     J
@@ -1123,7 +1123,7 @@ USD(7.92) -7.92   USD     CJ
 -8 USD -8      USD     C
 67 USD 67      USD
 // J throws a NullPointerException on the next case
-53.45$ fail    USD
+53.45$ fail    USD     P
 US Dollars 53.45       53.45   USD     J
 53.45 US Dollars       53.45   USD
 US Dollar 53.45        53.45   USD     J
@@ -1142,7 +1142,7 @@ begin
 parse  output  outputCurrency  breaks
 53.45  fail    GBP
 £53.45        53.45   GBP
-$53.45 fail    USD     J
+$53.45 fail    USD     JP
 53.45 USD      53.45   USD
 53.45 GBP      53.45   GBP
 USD 53.45      53.45   USD     J
@@ -1160,7 +1160,7 @@ USD(7.92) -7.92   USD     CJ
 (8) USD        -8      USD
 -8 USD -8      USD     C
 67 USD 67      USD
-53.45$ fail    USD
+53.45$ fail    USD     P
 US Dollars 53.45       53.45   USD     J
 53.45 US Dollars       53.45   USD
 US Dollar 53.45        53.45   USD     J
@@ -1179,7 +1179,7 @@ begin
 parse  output  outputCurrency  breaks
 53.45  fail    GBP
 £53.45        53.45   GBP
-$53.45 fail    USD     J
+$53.45 fail    USD     JP
 53.45 USD      53.45   USD     C
 53.45 GBP      53.45   GBP     C
 USD 53.45      53.45   USD     J
@@ -1198,7 +1198,7 @@ USD(7.92) -7.92   USD     CJP
 (8) USD        -8      USD     CJP
 -8 USD -8      USD     C
 67 USD 67      USD     C
-53.45$ fail    USD
+53.45$ fail    USD     P
 US Dollars 53.45       53.45   USD     J
 53.45 US Dollars       53.45   USD
 US Dollar 53.45        53.45   USD     J
@@ -1604,6 +1604,24 @@ lenient  parse   output  breaks
 0      0       fail    CJK
 0      +0      0       CJK
 
+test parse lowercase currency
+set locale en
+set pattern ¤¤0
+set currency USD
+begin
+parse  output  outputCurrency  breaks
+USD123 123     USD
+USD 123        123     USD     J
+usd123 123     USD
+usd 123        123     USD     J
+Usd123 123     USD
+Usd 123        123     USD     J
+US$123 123     USD
+us$123 fail    fail
+Us$123 fail    fail
+123 US dollars 123     USD
+123 US DOLLARS 123     USD
+123 us dollars 123     USD
 
 
 
index d8be411eb9db4a2ed704edeed0dd2cf0c0cbbbe1..3a38ffde9c52ac26243a83045e7f305cdfa8346d 100644 (file)
@@ -663,6 +663,9 @@ public class NumberFormatDataDrivenTest {
                 if (ppos.getIndex() == 0 || actual.getCurrency().getCurrencyCode().equals("XXX")) {
                     return "Parse failed; got " + actual + ", but expected " + tuple.output;
                 }
+                if (tuple.output.equals("fail")) {
+                    return null;
+                }
                 BigDecimal expectedNumber = new BigDecimal(tuple.output);
                 if (expectedNumber.compareTo(new BigDecimal(actual.getNumber().toString())) != 0) {
                     return "Wrong number: Expected: " + expectedNumber + ", got: " + actual;
index 639744aed436a966701aa210cb426fb107de5e32..d1386fcb87bf27d71a197f73e91d1c2b0e719b99 100644 (file)
@@ -6017,4 +6017,14 @@ public class NumberFormatTest extends TestFmwk {
         df.setParseStrict(true);
         expect2(df, -51.42, "-US$ 51.42");
     }
+
+    @Test
+    public void testCaseSensitiveCustomIsoCurrency() {
+        DecimalFormat df = new DecimalFormat("¤¤0", DecimalFormatSymbols.getInstance(ULocale.ENGLISH));
+        df.setCurrency(Currency.getInstance("ICU"));
+        ParsePosition ppos = new ParsePosition(0);
+        df.parseCurrency("icu123", ppos);
+        assertEquals("Should fail to parse", 0, ppos.getIndex());
+        assertEquals("Should fail to parse", 0, ppos.getErrorIndex());
+    }
 }