From da65d09dd550b1b581badf75e8bcd275ebca27b8 Mon Sep 17 00:00:00 2001 From: Shane Carr Date: Tue, 30 Jan 2018 01:21:56 +0000 Subject: [PATCH] ICU-13513 A few more minor fixes before merge. X-SVN-Rev: 40822 --- .../impl/number/parse/NumberParserImpl.java | 75 ++++++++-------- .../parse/RequireDecimalSeparatorMatcher.java | 16 +++- .../number/DecimalQuantity_SimpleStorage.java | 2 + .../icu/dev/test/format/NumberFormatTest.java | 86 +------------------ 4 files changed, 52 insertions(+), 127 deletions(-) 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 005ba8e8ea..59bcdd09a5 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 @@ -34,37 +34,36 @@ public class NumberParserImpl { // TODO: Find a better place for this enum. /** Controls the set of rules for parsing a string. */ public static enum ParseMode { - /** - * Lenient mode should be used if you want to accept malformed user input. It will use - * heuristics to attempt to parse through typographical errors in the string. - */ - LENIENT, + /** + * Lenient mode should be used if you want to accept malformed user input. It will use heuristics + * to attempt to parse through typographical errors in the string. + */ + LENIENT, - /** - * Strict mode should be used if you want to require that the input is well-formed. More - * specifically, it differs from lenient mode in the following ways: - * - * - */ - STRICT, + /** + * Strict mode should be used if you want to require that the input is well-formed. More + * specifically, it differs from lenient mode in the following ways: + * + * + */ + STRICT, } @Deprecated @@ -167,20 +166,12 @@ public class NumberParserImpl { AffixPatternProvider patternInfo = new PropertiesAffixPatternProvider(properties); Currency currency = CustomSymbolCurrency.resolve(properties.getCurrency(), locale, symbols); boolean isStrict = properties.getParseMode() == ParseMode.STRICT; - boolean decimalSeparatorRequired = properties.getDecimalPatternMatchRequired() - ? (properties.getDecimalSeparatorAlwaysShown() - || properties.getMaximumFractionDigits() != 0) - : false; - boolean decimalSeparatorForbidden = properties.getDecimalPatternMatchRequired() - ? (!properties.getDecimalSeparatorAlwaysShown() - && properties.getMaximumFractionDigits() == 0) - : false; Grouper grouper = Grouper.defaults().withProperties(properties); int parseFlags = 0; if (!properties.getParseCaseSensitive()) { parseFlags |= ParsingUtils.PARSE_FLAG_IGNORE_CASE; } - if (properties.getParseIntegerOnly() || decimalSeparatorForbidden) { + if (properties.getParseIntegerOnly()) { parseFlags |= ParsingUtils.PARSE_FLAG_INTEGER_ONLY; } if (isStrict) { @@ -260,8 +251,10 @@ public class NumberParserImpl { if (parseCurrency) { parser.addMatcher(new RequireCurrencyMatcher()); } - if (decimalSeparatorRequired) { - parser.addMatcher(new RequireDecimalSeparatorMatcher()); + if (properties.getDecimalPatternMatchRequired()) { + boolean patternHasDecimalSeparator = properties.getDecimalSeparatorAlwaysShown() + || properties.getMaximumFractionDigits() != 0; + parser.addMatcher(RequireDecimalSeparatorMatcher.getInstance(patternHasDecimalSeparator)); } if (properties.getMultiplier() != null) { // We need to use a math context in order to prevent non-terminating decimal expansions. diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/RequireDecimalSeparatorMatcher.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/RequireDecimalSeparatorMatcher.java index 0bbe5b2972..6c536e8c09 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/RequireDecimalSeparatorMatcher.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/RequireDecimalSeparatorMatcher.java @@ -8,9 +8,23 @@ package com.ibm.icu.impl.number.parse; */ public class RequireDecimalSeparatorMatcher extends ValidationMatcher { + private static final RequireDecimalSeparatorMatcher A = new RequireDecimalSeparatorMatcher(true); + private static final RequireDecimalSeparatorMatcher B = new RequireDecimalSeparatorMatcher(false); + + private final boolean patternHasDecimalSeparator; + + public static RequireDecimalSeparatorMatcher getInstance(boolean patternHasDecimalSeparator) { + return patternHasDecimalSeparator ? A : B; + } + + private RequireDecimalSeparatorMatcher(boolean patternHasDecimalSeparator) { + this.patternHasDecimalSeparator = patternHasDecimalSeparator; + } + @Override public void postProcess(ParsedNumber result) { - if (0 == (result.flags & ParsedNumber.FLAG_HAS_DECIMAL_SEPARATOR)) { + boolean parseHasDecimalSeparator = 0 != (result.flags & ParsedNumber.FLAG_HAS_DECIMAL_SEPARATOR); + if (parseHasDecimalSeparator != patternHasDecimalSeparator) { result.flags |= ParsedNumber.FLAG_FAIL; } } diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/impl/number/DecimalQuantity_SimpleStorage.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/impl/number/DecimalQuantity_SimpleStorage.java index 406a210944..c4db104e5f 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/impl/number/DecimalQuantity_SimpleStorage.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/impl/number/DecimalQuantity_SimpleStorage.java @@ -8,6 +8,8 @@ import java.math.RoundingMode; import java.text.FieldPosition; import com.ibm.icu.impl.StandardPlural; +import com.ibm.icu.impl.number.DecimalQuantity; +import com.ibm.icu.impl.number.RoundingUtils; import com.ibm.icu.text.PluralRules; import com.ibm.icu.text.PluralRules.Operand; import com.ibm.icu.text.UFieldPosition; 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 13b4d91128..524ac2ce4e 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 @@ -4250,7 +4250,6 @@ public class NumberFormatTest extends TestFmwk { } @Test - @Ignore public void TestParseRequiredDecimalPoint() { String[] testPattern = { "00.####", "00.0", "00" }; @@ -5466,7 +5465,6 @@ public class NumberFormatTest extends TestFmwk { } @Test - @Ignore public void testParseSubtraction() { // TODO: Is this a case we need to support? It prevents us from automatically parsing // minus signs that appear after the number, like in "12-" vs "-12". @@ -5499,6 +5497,7 @@ public class NumberFormatTest extends TestFmwk { assertEquals("Quote should be escapable in padding syntax", "a''12b", result); } + // TODO: Investigate this test and re-enable if appropriate. @Test @Ignore public void testParseAmbiguousAffixes() { @@ -5648,89 +5647,6 @@ public class NumberFormatTest extends TestFmwk { } } - @Test - @Ignore - public void testParseGroupingMode() { - ULocale[] locales = { // GROUPING DECIMAL - new ULocale("en-US"), // comma period - new ULocale("fr-FR"), // space comma - new ULocale("de-CH"), // apostrophe period - new ULocale("es-PY") // period comma - }; - String[] inputs = { - "12,345.67", - "12 345,67", - "12'345.67", - "12.345,67", - "12,345", - "12 345", - "12'345", - "12.345" - }; - BigDecimal[] outputs = { - new BigDecimal("12345.67"), - new BigDecimal("12345.67"), - new BigDecimal("12345.67"), - new BigDecimal("12345.67"), - new BigDecimal("12345"), - new BigDecimal("12345"), - new BigDecimal("12345"), - new BigDecimal("12345") - }; - int[][] expecteds = { - // 0 => works in neither default nor restricted - // 1 => works in default but not restricted - // 2 => works in restricted but not default (should not happen) - // 3 => works in both default and restricted - // - // C=comma, P=period, S=space, A=apostrophe - // C+P S+C A+P P+C C-only S-only A-only P-only - { 3, 0, 1, 0, 3, 1, 1, 0 }, // => en-US - { 0, 3, 0, 1, 0, 3, 3, 1 }, // => fr-FR - { 1, 0, 3, 0, 1, 3, 3, 0 }, // => de-CH - { 0, 1, 0, 3, 0, 1, 1, 3 } // => es-PY - }; - - for (int i=0; i