diff options
author | Shane Carr <sffc@google.com> | 2018-04-12 20:14:23 +0000 |
---|---|---|
committer | Fredrik Roubert <roubert@google.com> | 2018-05-31 16:40:00 -0700 |
commit | 922b004e37b8dc53e772a4574d28611532855829 (patch) | |
tree | a06f81c8d68838c96a2ceeb89c4a42405645e7fc | |
parent | e1021107e043e13a7ef6b77aaf2c54ebbd82c479 (diff) | |
download | icu-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
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()); + } + } } |