summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShane Carr <sffc@google.com>2018-04-12 20:14:23 +0000
committerFredrik Roubert <roubert@google.com>2018-05-31 16:40:00 -0700
commit922b004e37b8dc53e772a4574d28611532855829 (patch)
treea06f81c8d68838c96a2ceeb89c4a42405645e7fc
parente1021107e043e13a7ef6b77aaf2c54ebbd82c479 (diff)
downloadicu-922b004e37b8dc53e772a4574d28611532855829.tar.gz
Android patch: ticket:13634 In accordance with ICU-TC meeting, changing percent parsing behavior to be closer to that of ICU 60.
This is a temporary work-around while waiting for ICU 62 to fix this. Changes copied manually from a development branch: http://bugs.icu-project.org/trac/changeset/41222 Change-Id: I2ec9e8c0ea85684acae9f4d1156b4b68516b305e
-rw-r--r--icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/FlagHandler.java28
-rw-r--r--icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java22
-rw-r--r--icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberformattestspecification.txt4
-rw-r--r--icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java30
4 files changed, 78 insertions, 6 deletions
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/FlagHandler.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/FlagHandler.java
new file mode 100644
index 000000000..37d39113a
--- /dev/null
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/FlagHandler.java
@@ -0,0 +1,28 @@
+// © 2018 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.impl.number.parse;
+
+/**
+ * Unconditionally applies a given set of flags to the ParsedNumber in the post-processing step.
+ */
+public class FlagHandler extends ValidationMatcher {
+
+ public static final FlagHandler PERCENT = new FlagHandler(ParsedNumber.FLAG_PERCENT);
+ public static final FlagHandler PERMILLE = new FlagHandler(ParsedNumber.FLAG_PERMILLE);
+
+ private final int flags;
+
+ private FlagHandler(int flags) {
+ this.flags = flags;
+ }
+
+ @Override
+ public void postProcess(ParsedNumber result) {
+ result.flags |= flags;
+ }
+
+ @Override
+ public String toString() {
+ return "<FlagsHandler " + Integer.toHexString(flags) + ">";
+ }
+}
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java
index 36fc84041..a614a3bbc 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java
@@ -10,6 +10,7 @@ import java.util.List;
import com.ibm.icu.impl.StringSegment;
import com.ibm.icu.impl.number.AffixPatternProvider;
+import com.ibm.icu.impl.number.AffixUtils;
import com.ibm.icu.impl.number.CustomSymbolCurrency;
import com.ibm.icu.impl.number.DecimalFormatProperties;
import com.ibm.icu.impl.number.Grouper;
@@ -247,6 +248,23 @@ public class NumberParserImpl {
parser.addMatcher(CurrencyTrieMatcher.getInstance(locale));
}
+ ///////////////
+ /// PERCENT ///
+ ///////////////
+
+ // 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 (patternInfo.containsSymbolType(AffixUtils.TYPE_PERCENT)) {
+ parser.addMatcher(PercentMatcher.getInstance(symbols));
+ // causes number to be always scaled by 100:
+ parser.addMatcher(FlagHandler.PERCENT);
+ }
+ if (patternInfo.containsSymbolType(AffixUtils.TYPE_PERMILLE)) {
+ parser.addMatcher(PermilleMatcher.getInstance(symbols));
+ // causes number to be always scaled by 1000:
+ parser.addMatcher(FlagHandler.PERMILLE);
+ }
+
///////////////////////////////
/// OTHER STANDARD MATCHERS ///
///////////////////////////////
@@ -254,10 +272,8 @@ public class NumberParserImpl {
if (!isStrict) {
parser.addMatcher(PlusSignMatcher.getInstance(symbols, false));
parser.addMatcher(MinusSignMatcher.getInstance(symbols, false));
- parser.addMatcher(NanMatcher.getInstance(symbols, parseFlags));
- parser.addMatcher(PercentMatcher.getInstance(symbols));
- parser.addMatcher(PermilleMatcher.getInstance(symbols));
}
+ parser.addMatcher(NanMatcher.getInstance(symbols, parseFlags));
parser.addMatcher(InfinityMatcher.getInstance(symbols));
String padString = properties.getPadString();
if (padString != null && !ignorables.getSet().contains(padString)) {
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberformattestspecification.txt b/icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberformattestspecification.txt
index b38a420f2..65dde7a6a 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberformattestspecification.txt
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/data/numberformattestspecification.txt
@@ -1545,8 +1545,8 @@ begin
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
+// C and P scale by 100 even if the percent sign is not present
+55 0.55 JK
test trailing grouping separators in pattern
// This test is for #13115
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java
index 4f0369bde..8906629ec 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java
@@ -5586,7 +5586,7 @@ public class NumberFormatTest extends TestFmwk {
assertEquals("Should consume the trailing bidi since it is in the symbol", 5, ppos.getIndex());
ppos.setIndex(0);
result = df.parse("-42a\u200E ", ppos);
- assertEquals("Should not parse as percent", new Long(-42), result);
+ assertEquals("Should parse as percent", -0.42, result.doubleValue());
assertEquals("Should not consume the trailing bidi or whitespace", 4, ppos.getIndex());
// A few more cases based on the docstring:
@@ -5944,4 +5944,32 @@ public class NumberFormatTest extends TestFmwk {
assertEquals("Should parse successfully", 0.08, percentage.doubleValue());
assertEquals("Should consume whole string", 3, ppos.getIndex());
}
+
+ @Test
+ public void testParsePercentRegression() {
+ DecimalFormat df1 = (DecimalFormat) NumberFormat.getInstance(ULocale.ENGLISH);
+ DecimalFormat df2 = (DecimalFormat) NumberFormat.getPercentInstance(ULocale.ENGLISH);
+ df1.setParseStrict(false);
+ df2.setParseStrict(false);
+
+ {
+ ParsePosition ppos = new ParsePosition(0);
+ Number result = df1.parse("50%", ppos);
+ assertEquals("df1 should accept a number but not the percent sign", 2, ppos.getIndex());
+ assertEquals("df1 should return the number as 50", 50.0, result.doubleValue());
+ }
+ {
+ ParsePosition ppos = new ParsePosition(0);
+ Number result = df2.parse("50%", ppos);
+ assertEquals("df2 should accept the percent sign", 3, ppos.getIndex());
+ assertEquals("df2 should return the number as 0.5", 0.5, result.doubleValue());
+ }
+ {
+ ParsePosition ppos = new ParsePosition(0);
+ Number result = df2.parse("50", ppos);
+ assertEquals("df2 should return the number as 0.5 even though the percent sign is missing",
+ 0.5,
+ result.doubleValue());
+ }
+ }
}