// [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ]
0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000};
+static const UChar gDashEquivalentsPattern[] = {
+ // [ \ - HYPHEN F_DASH N_DASH MINUS ]
+ 0x005B, 0x005C, 0x002D, 0x2010, 0x2012, 0x2013, 0x2212, 0x005D, 0x0000};
+
static const UChar gStrictDotEquivalentsPattern[] = {
// [ . \u2024 \uFE52 \uFF0E \uFF61 ]
0x005B, 0x002E, 0x2024, 0xFE52, 0xFF0E, 0xFF61, 0x005D, 0x0000};
// [ \ SPACE ' NBSP \u066C \u2000 - \u200A \u2018 \u2019 \u202F \u205F \u3000 \uFF07 ]
0x005B, 0x005C, 0x0020, 0x0027, 0x00A0, 0x066C, 0x2000, 0x002D, 0x200A, 0x2018, 0x2019, 0x202F, 0x205F, 0x3000, 0xFF07, 0x005D, 0x0000};
+static const UChar gStrictDashEquivalentsPattern[] = {
+ // [ \ - MINUS ]
+ 0x005B, 0x005C, 0x002D, 0x2212, 0x005D, 0x0000};
+
DecimalFormatStaticSets *DecimalFormatStaticSets::gStaticSets = NULL;
: fDotEquivalents(NULL),
fCommaEquivalents(NULL),
fOtherGroupingSeparators(NULL),
+ fDashEquivalents(NULL),
fStrictDotEquivalents(NULL),
fStrictCommaEquivalents(NULL),
fStrictOtherGroupingSeparators(NULL),
+ fStrictDashEquivalents(NULL),
fDefaultGroupingSeparators(NULL),
fStrictDefaultGroupingSeparators(NULL)
{
fDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1), *status);
fCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1), *status);
fOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1), *status);
+ fDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1), *status);
+
fStrictDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1), *status);
fStrictCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1), *status);
fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), *status);
+ fStrictDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1), *status);
fDefaultGroupingSeparators = new UnicodeSet(*fDotEquivalents);
fStrictDefaultGroupingSeparators->addAll(*fStrictOtherGroupingSeparators);
// Check for null pointers
- if (fDotEquivalents == NULL || fCommaEquivalents == NULL || fOtherGroupingSeparators == NULL ||
- fStrictDotEquivalents == NULL || fStrictCommaEquivalents == NULL || fStrictOtherGroupingSeparators == NULL ||
+ if (fDotEquivalents == NULL || fCommaEquivalents == NULL || fOtherGroupingSeparators == NULL || fDashEquivalents == NULL ||
+ fStrictDotEquivalents == NULL || fStrictCommaEquivalents == NULL || fStrictOtherGroupingSeparators == NULL || fStrictDashEquivalents == NULL ||
fDefaultGroupingSeparators == NULL || fStrictOtherGroupingSeparators == NULL) {
goto ExitConstrDeleteAll;
}
fDotEquivalents->freeze();
fCommaEquivalents->freeze();
fOtherGroupingSeparators->freeze();
+ fDashEquivalents->freeze();
fStrictDotEquivalents->freeze();
fStrictCommaEquivalents->freeze();
fStrictOtherGroupingSeparators->freeze();
+ fStrictDashEquivalents->freeze();
fDefaultGroupingSeparators->freeze();
fStrictDefaultGroupingSeparators->freeze();
delete fDotEquivalents; fDotEquivalents = NULL;
delete fCommaEquivalents; fCommaEquivalents = NULL;
delete fOtherGroupingSeparators; fOtherGroupingSeparators = NULL;
+ delete fDashEquivalents; fDashEquivalents = NULL;
delete fStrictDotEquivalents; fStrictDotEquivalents = NULL;
delete fStrictCommaEquivalents; fStrictCommaEquivalents = NULL;
delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
+ delete fStrictDashEquivalents; fStrictDashEquivalents = NULL;
delete fDefaultGroupingSeparators; fDefaultGroupingSeparators = NULL;
delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
delete fDotEquivalents; fDotEquivalents = NULL;
delete fCommaEquivalents; fCommaEquivalents = NULL;
delete fOtherGroupingSeparators; fOtherGroupingSeparators = NULL;
+ delete fDashEquivalents; fDashEquivalents = NULL;
delete fStrictDotEquivalents; fStrictDotEquivalents = NULL;
delete fStrictCommaEquivalents; fStrictCommaEquivalents = NULL;
delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
+ delete fStrictDashEquivalents; fStrictDashEquivalents = NULL;
delete fDefaultGroupingSeparators; fDefaultGroupingSeparators = NULL;
delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL;
}
UnicodeSet *fDotEquivalents;
UnicodeSet *fCommaEquivalents;
UnicodeSet *fOtherGroupingSeparators;
+ UnicodeSet *fDashEquivalents;
UnicodeSet *fStrictDotEquivalents;
UnicodeSet *fStrictCommaEquivalents;
UnicodeSet *fStrictOtherGroupingSeparators;
+ UnicodeSet *fStrictDashEquivalents;
UnicodeSet *fDefaultGroupingSeparators;
UnicodeSet *fStrictDefaultGroupingSeparators;
position += U16_LENGTH(ch);
}
- else if (matchSymbol(text, position, groupingStringLength, *groupingString, groupingSet, ch) && isGroupingUsed())
+ else if (groupingStringLength > 0 && matchSymbol(text, position, groupingStringLength, *groupingString, groupingSet, ch) && isGroupingUsed())
{
#if CHECK_FOR_MISPLACED_GROUPING
if (sawDecimal) {
const UnicodeString& input,
int32_t pos,
UBool strict) {
+ UErrorCode status = U_ZERO_ERROR;
int32_t start = pos;
+ UChar32 affixChar = affix.char32At(0);
+ int32_t affixLength = affix.length();
+ int32_t inputLength = input.length();
+ int32_t affixCharLength = U16_LENGTH(affixChar);
+ UnicodeSet *affixSet;
+ DecimalFormatStaticSets::initSets(&status);
+
if (strict) {
- for (int32_t i=0; i<affix.length(); ) {
+ affixSet = DecimalFormatStaticSets::gStaticSets->fStrictDashEquivalents;
+
+ // If the affix is exactly one character long and that character
+ // is in the dash set and the very next input character is also
+ // in the dash set, return a match.
+ if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
+ if (affixSet->contains(input.char32At(pos))) {
+ return 1;
+ }
+ }
+
+ for (int32_t i=0; i<affixLength; ) {
UChar32 c = affix.char32At(i);
int32_t len = U16_LENGTH(c);
if (uprv_isRuleWhiteSpace(c)) {
// match of the run of RULE whitespace in the pattern,
// then match any extra characters.
UBool literalMatch = FALSE;
- while (pos < input.length() &&
+ while (pos < inputLength &&
input.char32At(pos) == c) {
literalMatch = TRUE;
i += len;
pos += len;
- if (i == affix.length()) {
+ if (i == affixLength) {
break;
}
c = affix.char32At(i);
// is also in the affix.
i = skipUWhiteSpace(affix, i);
} else {
- if (pos < input.length() &&
+ if (pos < inputLength &&
input.char32At(pos) == c) {
i += len;
pos += len;
}
}
} else {
- int32_t affixLength = affix.length();
- int32_t inputLength = input.length();
UBool match = FALSE;
+
+ affixSet = DecimalFormatStaticSets::gStaticSets->fDashEquivalents;
+
+ if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
+ pos = skipUWhiteSpace(input, pos);
+
+ if (affixSet->contains(input.char32At(pos))) {
+ return pos - start + 1;
+ }
+ }
for (int32_t i = 0; i < affixLength; )
{
// in strict mode, these can only
// be a number if count <= 2
if (!lenient && gotNumber && count > 2) {
- return -1;
+ // We have a string pattern in strict mode
+ // but the input parsed as a number. Ignore
+ // the fact that the input parsed as a number
+ // and try to match it as a string. (Some
+ // locales have numbers for the month names.)
+ gotNumber = FALSE;
+ pos.setIndex(start);
}
break;
/*
TESTCASE(37,TestRelativeError);
TESTCASE(38,TestRelativeOther);
- */
+ TESTCASE(39,TestNumberAsStringParsing);
+ */
+ TESTCASE(37,TestNumberAsStringParsing);
default: name = ""; break;
}
}
}
*/
+void DateFormatTest::TestNumberAsStringParsing()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString dateString("2009 7 2 08:14:16");
+ UnicodeString datePattern("y MMMM d HH:mm:ss");
+ SimpleDateFormat *formatter = new SimpleDateFormat(datePattern, Locale(""), status);
+ UDate date1 = 0;
+
+ formatter->setLenient(FALSE);
+ date1 = formatter->parse(dateString, status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: Could not parse \"2009 7 2 08:14:16\" with pattern \"y MMMM d HH:mm:ss\"");
+ } else {
+ UnicodeString formatted;
+
+ formatter->format(date1, formatted);
+
+ if (formatted != dateString) {
+ errln("FAIL: parsed string did not match input.");
+ }
+ }
+
+ delete formatter;
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
/********************************************************************
* COPYRIGHT:
- * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * Copyright (c) 1997-2009, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
virtual void TestDateFormatZone146(void);
void TestTimeZoneStringsAPI(void);
-
+
+#if ICU_4_2_1
+ void TestGMTParsing(void);
+#endif
+
public: // package
/**
* Test the formatting of dates in different locales.
void TestGenericTimeZoneOrder(void);
+#if ICU_4_2_1
+ void Test6338(void);
+
+ void Test6726(void);
+
+ void Test6880(void);
+#endif
+
public:
/**
* Test host-specific formatting.
void TestHostClone(void);
+#if ICU_4_2_1
+ void TestTimeZoneDisplayName(void);
+
+ void TestRoundtripWithCalendar(void);
+#endif
+
public:
/***
* Test Relative Dates
*/
void TestRelative(void);
- void TestTimeZoneDisplayName(void);
+#if !ICU_4_2_1
+ void TestTimeZoneDisplayName(void);
+#endif
/* void TestRelativeError(void);
void TestRelativeOther(void);
*/
- private:
+public:
+ /**
+ * Test parsing a number as a string
+ */
+ void TestNumberAsStringParsing(void);
+
+private:
void TestRelative(int daysdelta,
const Locale& loc,
const char *expectChars);
"( 1 )"
};
+static const char *lenientMinusTestCases[] = {
+ "-5",
+ "\\u22125",
+ "\\u20105"
+};
+
static const char *lenientCurrencyTestCases[] = {
"$1,000",
"$ 1,000",
delete format;
- Locale locale("en_US");
- NumberFormat *cFormat = NumberFormat::createCurrencyInstance(locale, status);
+ Locale en_US("en_US");
+ Locale sv_SE("sv_SE");
+
+ NumberFormat *mFormat = NumberFormat::createInstance(sv_SE, status);
+
+ mFormat->setParseStrict(FALSE);
+ for (int32_t t = 0; t < ARRAY_SIZE(lenientMinusTestCases); t += 1) {
+ UnicodeString testCase = ctou(lenientMinusTestCases[t]);
+
+ mFormat->parse(testCase, n, status);
+ logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
+
+ if (U_FAILURE(status) || n.getType() != Formattable::kLong || n.getLong() != -5) {
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t] + (UnicodeString) "\"");
+ status = U_ZERO_ERROR;
+ }
+ }
+
+ delete mFormat;
+
+ mFormat = NumberFormat::createInstance(en_US, status);
+
+ mFormat->setParseStrict(FALSE);
+ for (int32_t t = 0; t < ARRAY_SIZE(lenientMinusTestCases); t += 1) {
+ UnicodeString testCase = ctou(lenientMinusTestCases[t]);
+
+ mFormat->parse(testCase, n, status);
+ logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
+
+ if (U_FAILURE(status) || n.getType() != Formattable::kLong || n.getLong() != -5) {
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t] + (UnicodeString) "\"");
+ status = U_ZERO_ERROR;
+ }
+ }
+
+ delete mFormat;
+
+ NumberFormat *cFormat = NumberFormat::createCurrencyInstance(en_US, status);
cFormat->setParseStrict(FALSE);
for (int32_t t = 0; t < ARRAY_SIZE (lenientCurrencyTestCases); t += 1) {
delete cFormat;
- NumberFormat *pFormat = NumberFormat::createPercentInstance(locale, status);
+ NumberFormat *pFormat = NumberFormat::createPercentInstance(en_US, status);
pFormat->setParseStrict(FALSE);
for (int32_t t = 0; t < ARRAY_SIZE (lenientPercentTestCases); t += 1) {
// Test cases that should fail with a strict parse and pass with a
// lenient parse.
- NumberFormat *nFormat = NumberFormat::createInstance(locale, status);
+ NumberFormat *nFormat = NumberFormat::createInstance(en_US, status);
// first, make sure that they fail with a strict parse
for (int32_t t = 0; t < ARRAY_SIZE(strictFailureTestCases); t += 1) {