]> granicus.if.org Git - icu/commitdiff
ICU-10970 Support required decimal point
authorScott Russell <DTownSMR@gmail.com>
Sat, 30 Aug 2014 21:53:10 +0000 (21:53 +0000)
committerScott Russell <DTownSMR@gmail.com>
Sat, 30 Aug 2014 21:53:10 +0000 (21:53 +0000)
X-SVN-Rev: 36300

icu4c/source/i18n/decimfmt.cpp
icu4c/source/i18n/unicode/decimfmt.h
icu4c/source/i18n/unicode/unum.h
icu4c/source/test/intltest/dcfmapts.cpp
icu4c/source/test/intltest/dcfmapts.h

index ade906573d6749bea45461c324966fa32469da96..da1f8d29f37e316716815f6c65910fbdd1d5b4b6 100644 (file)
@@ -2944,6 +2944,18 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
             }
         }
 
+        // if we didn't see a decimal and it is required, check to see if the pattern had one
+        if(!sawDecimal && isDecimalPatternMatchRequired()) 
+        {
+            if(fFormatPattern.indexOf(DecimalFormatSymbols::kDecimalSeparatorSymbol) != 0) 
+            {
+                parsePosition.setIndex(oldStart);
+                parsePosition.setErrorIndex(position);
+                debug("decimal point match required fail!");
+                return FALSE;
+            }
+        }
+
         if (backup != -1)
         {
             position = backup;
@@ -3057,6 +3069,20 @@ printf("PP -> %d, SLOW = [%s]!    pp=%d, os=%d, err=%s\n", position, parsedNum.d
         parsePosition.setErrorIndex(position);
         return FALSE;
     }
+
+    // check if we missed a required decimal point
+    if(fastParseOk && isDecimalPatternMatchRequired()) 
+    {
+        if(fFormatPattern.indexOf(DecimalFormatSymbols::kDecimalSeparatorSymbol) != 0) 
+        {
+            parsePosition.setIndex(oldStart);
+            parsePosition.setErrorIndex(position);
+            debug("decimal point match required fail!");
+            return FALSE;
+        }
+    }
+
+
     return TRUE;
 }
 
@@ -4168,6 +4194,24 @@ DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue)
 #endif
 }
 
+//------------------------------------------------------------------------------
+// Checks if decimal point pattern match is required
+UBool 
+DecimalFormat::isDecimalPatternMatchRequired(void) const
+{
+    return fBoolFlags.contains(UNUM_PARSE_DECIMAL_MARK_REQUIRED);
+}
+
+//------------------------------------------------------------------------------
+// Checks if decimal point pattern match is required
+         
+void 
+DecimalFormat::setDecimalPatternMatchRequired(UBool newValue)
+{
+    fBoolFlags.set(UNUM_PARSE_DECIMAL_MARK_REQUIRED, newValue);
+}
+
+
 //------------------------------------------------------------------------------
 // Emits the pattern of this DecimalFormat instance.
 
@@ -5480,6 +5524,7 @@ DecimalFormat& DecimalFormat::setAttribute( UNumberFormatAttribute attr,
     /* These are stored in fBoolFlags */
     case UNUM_PARSE_NO_EXPONENT:
     case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+    case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
       if(!fBoolFlags.isValidValue(newValue)) {
           status = U_ILLEGAL_ARGUMENT_ERROR;
       } else {
@@ -5567,6 +5612,7 @@ int32_t DecimalFormat::getAttribute( UNumberFormatAttribute attr,
     /* These are stored in fBoolFlags */
     case UNUM_PARSE_NO_EXPONENT:
     case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+    case UNUM_PARSE_DECIMAL_MARK_REQUIRED:
       return fBoolFlags.get(attr);
 
     case UNUM_SCALE:
index 9c22dc6c0f88390c8b5365cfe4d01464a61a6414..116d65c93fe6f6d89a62e23a72662d3d355b8294 100644 (file)
@@ -1631,6 +1631,26 @@ public:
      */
     virtual void setDecimalSeparatorAlwaysShown(UBool newValue);
 
+    /**
+     * Allows you to get the parse behavior of the pattern decimal mark.
+     *
+     * @return    TRUE if input must contain a match to decimal mark in pattern
+     * @draft ICU 54
+     */
+    UBool isDecimalPatternMatchRequired(void) const;
+
+    /**
+     * Allows you to set the behavior of the pattern decimal mark.
+     * 
+     * if TRUE, the input must have a decimal mark if one was specified in the pattern. When
+     * FALSE the decimal mark may be omitted from the input.
+     *
+     * @param newValue    set TRUE if input must contain a match to decimal mark in pattern
+     * @draft ICU 54
+     */
+    virtual void setDecimalPatternMatchRequired(UBool newValue);
+
+
     /**
      * Synthesizes a pattern string that represents the current state
      * of this Format object.
index f248c17871af72f3b446c39d230087b5473fe0df..27abadeb211cd5007c27613dcdbe38db5cd8af67 100644 (file)
@@ -940,6 +940,16 @@ typedef enum UNumberFormatAttribute {
    */
   UNUM_PARSE_NO_EXPONENT,
 
+  /** 
+   * if this attribute is set to 1, specifies that, if the pattern contains a 
+   * decimal mark the input is required to have one. If this attribute is set to 0,
+   * specifies that input does not have to contain a decimal mark.
+   * Has no effect on formatting.
+   * Default: 0 (unset)
+   * @draft ICU 54
+   */
+  UNUM_PARSE_DECIMAL_MARK_REQUIRED,
+
   /* The following cannot be #ifndef U_HIDE_INTERNAL_API, needed in .h file variable declararions */
   /** Limit of boolean attributes.
    * @internal */
index 0e651de50176fd87ae85f23e75cc44ca223f8a0d..e98cdd8d74953ad780acfd981da3f425f941b5ef 100644 (file)
@@ -79,6 +79,12 @@ void IntlTestDecimalFormatAPI::runIndexedTest( int32_t index, UBool exec, const
                TestBadFastpath();
             }
             break;
+         case 7: name = "TestRequiredDecimalPoint";
+            if(exec) {
+               logln((UnicodeString)"TestRequiredDecimalPoint ---");
+               TestRequiredDecimalPoint();
+            }
+            break;
        default: name = ""; break;
     }
 }
@@ -825,4 +831,52 @@ void IntlTestDecimalFormatAPI::TestBadFastpath() {
     assertEquals("Format 1234 w/ grouping", "1,234", df->format(1234, fmt));
 }
 
+void IntlTestDecimalFormatAPI::TestRequiredDecimalPoint() {
+    UErrorCode status = U_ZERO_ERROR;
+    UnicodeString text("99");
+    double expected = 99;
+    double whatIGot = 0.0;
+    Formattable result1;
+    UnicodeString pat1("##.0000");
+    UnicodeString pat2("00.0");
+
+    LocalPointer<DecimalFormat> df(new DecimalFormat(pat1, status));
+    if (U_FAILURE(status)) {
+        dataerrln("Error creating new DecimalFormat - %s", u_errorName(status));
+        return;
+    }
+    
+    status = U_ZERO_ERROR;
+    df->applyPattern(pat1, status);
+    if(U_FAILURE(status)) {
+        errln((UnicodeString)"ERROR: applyPattern() failed");
+    }
+    df->parse(text, result1, status);
+    if(U_FAILURE(status)) {
+        errln((UnicodeString)"ERROR: parse() failed");
+    }
+    df->setDecimalPatternMatchRequired(TRUE);
+    df->parse(text, result1, status);
+    if(U_SUCCESS(status)) {
+        errln((UnicodeString)"ERROR: unexpected parse()");
+    }
+    
+    
+    status = U_ZERO_ERROR;
+    df->applyPattern(pat2, status);
+    df->setDecimalPatternMatchRequired(FALSE);
+    if(U_FAILURE(status)) {
+        errln((UnicodeString)"ERROR: applyPattern(2) failed");
+    }
+    df->parse(text, result1, status);
+    if(U_FAILURE(status)) {
+        errln((UnicodeString)"ERROR: parse(2) failed - " + u_errorName(status));
+    }
+    df->setDecimalPatternMatchRequired(TRUE);
+    df->parse(text, result1, status);
+    if(U_SUCCESS(status)) {
+        errln((UnicodeString)"ERROR: unexpected parse(2)");
+    }
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 10be89fab251c6c1d81fa8327abdb8605a94b6b8..32e208a36ad20dce0c02fce3fcbba6555dad58d4 100644 (file)
@@ -30,6 +30,7 @@ public:
     void TestScale();
     void TestFixedDecimal();
     void TestBadFastpath();
+    void TestRequiredDecimalPoint();
 private:
     /*Helper functions */
     void verify(const UnicodeString& message, const UnicodeString& got, double expected);