ICU-20073 Do not parse stray percent sign in strict mode. (#145)
authorShane <sffc@sffc1.com>
Thu, 20 Sep 2018 21:47:25 +0000 (14:47 -0700)
committerShane Carr <shane@unicode.org>
Thu, 27 Sep 2018 21:27:41 +0000 (14:27 -0700)
icu4c/source/i18n/numparse_impl.cpp
icu4c/source/test/intltest/numfmtst.cpp
icu4c/source/test/intltest/numfmtst.h
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java

index 5fa52f63351c313e27637994e51c69815bf2c37f..3192a3959389a790a6e0944542570724306b89a5 100644 (file)
@@ -159,10 +159,10 @@ NumberParserImpl::createParserFromProperties(const number::impl::DecimalFormatPr
 
     // ICU-TC meeting, April 11, 2018: accept percent/permille only if it is in the pattern,
     // and to maintain regressive behavior, divide by 100 even if no percent sign is present.
-    if (affixProvider->containsSymbolType(AffixPatternType::TYPE_PERCENT, status)) {
+    if (!isStrict && affixProvider->containsSymbolType(AffixPatternType::TYPE_PERCENT, status)) {
         parser->addMatcher(parser->fLocalMatchers.percent = {symbols});
     }
-    if (affixProvider->containsSymbolType(AffixPatternType::TYPE_PERMILLE, status)) {
+    if (!isStrict && affixProvider->containsSymbolType(AffixPatternType::TYPE_PERMILLE, status)) {
         parser->addMatcher(parser->fLocalMatchers.permille = {symbols});
     }
 
index ecd6f95380db59b8f64293463159c31647330be9..2a4d91b84c0ff0de31d1f2843d780e5182a5f221 100644 (file)
@@ -202,6 +202,7 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n
   TESTCASE_AUTO(Test11645_ApplyPatternEquality);
   TESTCASE_AUTO(Test12567);
   TESTCASE_AUTO(Test11626_CustomizeCurrencyPluralInfo);
+  TESTCASE_AUTO(Test20073_StrictPercentParseErrorIndex);
   TESTCASE_AUTO(Test13056_GroupingSize);
   TESTCASE_AUTO(Test11025_CurrencyPadding);
   TESTCASE_AUTO(Test11648_ExpDecFormatMalPattern);
@@ -8942,6 +8943,17 @@ void NumberFormatTest::Test11626_CustomizeCurrencyPluralInfo() {
     assertEquals("Plural other", u"99 америчких долара", df.format(99, result.remove(), errorCode));
 }
 
+void NumberFormatTest::Test20073_StrictPercentParseErrorIndex() {
+    IcuTestErrorCode status(*this, "Test20073_StrictPercentParseErrorIndex");
+    ParsePosition parsePosition(0);
+    DecimalFormat df(u"0%", {"en-us", status}, status);
+    df.setLenient(FALSE);
+    Formattable result;
+    df.parse(u"%2%", result, parsePosition);
+    assertEquals("", 0, parsePosition.getIndex());
+    assertEquals("", 0, parsePosition.getErrorIndex());
+}
+
 void NumberFormatTest::Test13056_GroupingSize() {
     UErrorCode status = U_ZERO_ERROR;
     DecimalFormat df(u"#,##0", status);
index 65e0ffe8f3374ff65fc634b0a60d655dee6acce2..9d255383243bda3fe733ff123f594514306d181e 100644 (file)
@@ -266,6 +266,7 @@ class NumberFormatTest: public CalendarTimeZoneTest {
     void Test11645_ApplyPatternEquality();
     void Test12567();
     void Test11626_CustomizeCurrencyPluralInfo();
+    void Test20073_StrictPercentParseErrorIndex();
     void Test13056_GroupingSize();
     void Test11025_CurrencyPadding();
     void Test11648_ExpDecFormatMalPattern();
index fb717496f526356bb8a6e83921056bc2c7ad2944..f90775c7fcca25dc455c86785c429e5cd582e888 100644 (file)
@@ -209,10 +209,10 @@ public class NumberParserImpl {
 
         // ICU-TC meeting, April 11, 2018: accept percent/permille only if it is in the pattern,
         // and to maintain regressive behavior, divide by 100 even if no percent sign is present.
-        if (affixProvider.containsSymbolType(AffixUtils.TYPE_PERCENT)) {
+        if (!isStrict && affixProvider.containsSymbolType(AffixUtils.TYPE_PERCENT)) {
             parser.addMatcher(PercentMatcher.getInstance(symbols));
         }
-        if (affixProvider.containsSymbolType(AffixUtils.TYPE_PERMILLE)) {
+        if (!isStrict && affixProvider.containsSymbolType(AffixUtils.TYPE_PERMILLE)) {
             parser.addMatcher(PermilleMatcher.getInstance(symbols));
         }
 
@@ -274,7 +274,7 @@ public class NumberParserImpl {
      *            The parser settings defined in the PARSE_FLAG_* fields.
      */
     public NumberParserImpl(int parseFlags) {
-        matchers = new ArrayList<NumberParseMatcher>();
+        matchers = new ArrayList<>();
         this.parseFlags = parseFlags;
         frozen = false;
     }
index d276f1fc0b255157d4a76c021578b2cc894b624f..d656b60183240b6fb5eeab1c73003d9b710501cb 100644 (file)
@@ -5990,6 +5990,17 @@ public class NumberFormatTest extends TestFmwk {
         }
     }
 
+    @Test
+    public void Test20073_StrictPercentParseErrorIndex() {
+        ParsePosition parsePosition = new ParsePosition(0);
+        DecimalFormat df = new DecimalFormat("0%", DecimalFormatSymbols.getInstance(Locale.US));
+        df.setParseStrict(true);
+        Number number = df.parse("%2%", parsePosition);
+        assertNull("", number);
+        assertEquals("", 0, parsePosition.getIndex());
+        assertEquals("", 0, parsePosition.getErrorIndex());
+    }
+
     @Test
     public void Test11626_CustomizeCurrencyPluralInfo() throws ParseException {
         // Use locale sr because it has interesting plural rules.