ICU-10970 Support required decimal point

X-SVN-Rev: 36300
This commit is contained in:
Scott Russell 2014-08-30 21:53:10 +00:00
parent 6dfe296e91
commit 867e55f0cb
5 changed files with 131 additions and 0 deletions

View 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:

View 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.

View 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 */

View 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 */

View 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);