]> granicus.if.org Git - icu/commitdiff
ICU-10258 Parse different variations of '+' and '-' when isLenient is set in C++.
authorTravis Keep <keep94@gmail.com>
Thu, 25 Jul 2013 17:58:37 +0000 (17:58 +0000)
committerTravis Keep <keep94@gmail.com>
Thu, 25 Jul 2013 17:58:37 +0000 (17:58 +0000)
X-SVN-Rev: 33989

icu4c/source/i18n/decimfmt.cpp
icu4c/source/test/intltest/numfmtst.cpp
icu4c/source/test/intltest/numfmtst.h

index cf6b2382be6b47c6dd91079f55af1aa2738f54ef..df2dc48fc4902bc1940102e42f012a723c4e4c2a 100644 (file)
@@ -282,6 +282,61 @@ static const char fgLatn[]="latn";
 static const char fgPatterns[]="patterns";
 static const char fgDecimalFormat[]="decimalFormat";
 static const char fgCurrencyFormat[]="currencyFormat";
+
+static UChar32 gMinusSigns[] = {
+    0x002D,
+    0x207B,
+    0x208B,
+    0x2212,
+    0x2796,
+    0xFE63,
+    0xFF0D};
+
+static UChar32 gPlusSigns[] = {
+    0x002B,
+    0x207A,
+    0x208A,
+    0x2795,
+    0xfB29,
+    0xFE62,
+    0xFF0B};
+
+static UnicodeSet *gMinusSignsSet = NULL;
+static UnicodeSet *gPlusSignsSet = NULL;
+
+static UInitOnce gSignsInitOnce = U_INITONCE_INITIALIZER;
+
+static void initSigns(const UChar32 *raw, int32_t len, UnicodeSet *s) {
+    for (int32_t i = 0; i < len; ++i) {
+        s->add(raw[i]);
+    }
+}
+
+static void U_CALLCONV initSigns() {
+    U_ASSERT(gMinusSignsSet == NULL);
+    U_ASSERT(gPlusSignsSet == NULL);
+    gMinusSignsSet = new UnicodeSet();
+    gPlusSignsSet = new UnicodeSet();
+    initSigns(
+            gMinusSigns,
+            sizeof(gMinusSigns) / sizeof(gMinusSigns[0]),
+            gMinusSignsSet);
+    initSigns(
+            gPlusSigns,
+            sizeof(gPlusSigns) / sizeof(gPlusSigns[0]),
+            gPlusSignsSet);
+}
+
+static const UnicodeSet* getMinusSigns() {
+    umtx_initOnce(gSignsInitOnce, &initSigns);
+    return gMinusSignsSet;
+}
+
+static const UnicodeSet* getPlusSigns() {
+    umtx_initOnce(gSignsInitOnce, &initSigns);
+    return gPlusSignsSet;
+}
+
 static const UChar fgTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
 
 inline int32_t _min(int32_t a, int32_t b) { return (a<b) ? a : b; }
@@ -2850,6 +2905,12 @@ int32_t DecimalFormat::compareAffix(const UnicodeString& text,
     return compareSimpleAffix(*patternToCompare, text, pos, isLenient());
 }
 
+static UBool equalWithSignCompatibility(UChar32 lhs, UChar32 rhs) {
+  return lhs == rhs
+      || (getMinusSigns()->contains(lhs) && getMinusSigns()->contains(rhs))
+      || (getPlusSigns()->contains(lhs) && getPlusSigns()->contains(rhs));
+}
+
 /**
  * Return the length matched by the given affix, or -1 if none.
  * Runs of white space in the affix, match runs of white space in
@@ -2966,7 +3027,7 @@ int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix,
             UChar32 c = affix.char32At(i);
             int32_t len = U16_LENGTH(c);
 
-            if (input.char32At(pos) != c) {
+            if (!equalWithSignCompatibility(input.char32At(pos), c)) {
                 return -1;
             }
 
index 3cc78fca58f87534aff39f96f0f39d54d3c11a26..803c326cf8c95c537919f9ef249a7478383b79ee 100644 (file)
@@ -126,6 +126,8 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n
   TESTCASE_AUTO(TestShowZero);
   TESTCASE_AUTO(TestCompatibleCurrencies);
   TESTCASE_AUTO(TestBug9936);
+  TESTCASE_AUTO(TestParseNegativeWithFaLocale);
+  TESTCASE_AUTO(TestParseNegativeWithAlternateMinusSign);
   TESTCASE_AUTO_END;
 }
 
@@ -7118,4 +7120,32 @@ void NumberFormatTest::TestBug9936() {
  
 }
 
+void NumberFormatTest::TestParseNegativeWithFaLocale() {
+    UErrorCode status = U_ZERO_ERROR;
+    DecimalFormat *test = (DecimalFormat *) NumberFormat::createInstance("fa", status);
+    test->setLenient(TRUE);
+    Formattable af;
+    ParsePosition ppos;
+    test->parse(UnicodeString("-0.5"), af, ppos);
+    if (ppos.getIndex() == 0) {
+        errln("Expected -0.5 to parse for farse.");
+    }
+    delete test;
+}
+
+void NumberFormatTest::TestParseNegativeWithAlternateMinusSign() {
+    UErrorCode status = U_ZERO_ERROR;
+    DecimalFormat *test = (DecimalFormat *) NumberFormat::createInstance("en", status);
+    test->setLenient(TRUE);
+    Formattable af;
+    ParsePosition ppos;
+    UnicodeString value("\\u208B0.5");
+    value = value.unescape();
+    test->parse(value, af, ppos);
+    if (ppos.getIndex() == 0) {
+        errln(UnicodeString("Expected ") + value + UnicodeString(" to parse."));
+    }
+    delete test;
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 48649b929ac6f975409fb05b37b3d53cc149d396..22b3b9f67a7a1ce2e8029217644d3e66941319c5 100644 (file)
@@ -169,6 +169,8 @@ class NumberFormatTest: public CalendarTimeZoneTest {
 
     void TestCompatibleCurrencies();
     void TestBug9936();
+    void TestParseNegativeWithFaLocale();
+    void TestParseNegativeWithAlternateMinusSign();
 
  private:
     UBool testFormattableAsUFormattable(const char *file, int line, Formattable &f);