}
}
} else {
- UChar ch = ovrField.charAt(0);
- UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
- UDateFormatField patternCharIndex;
-
// if the pattern character is unrecognized, signal an error and bail out
- if (patternCharPtr == NULL) {
+ UDateFormatField patternCharIndex =
+ DateFormatSymbols::getPatternCharIndex(ovrField.charAt(0));
+ if (patternCharIndex == UDAT_FIELD_COUNT) {
status = U_INVALID_FORMAT_ERROR;
return;
}
- patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
// Set the number formatter in the table
fNumberFormatters[patternCharIndex] = nf;
start = delimiterPosition + 1;
}
}
+
//---------------------------------------------------------------------
void
SimpleDateFormat::subFormat(UnicodeString &appendTo,
// this function gets called by format() to produce the appropriate substitution
// text for an individual pattern symbol (e.g., "HH" or "yyyy")
- UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
- UDateFormatField patternCharIndex;
+ UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
const int32_t maxIntCount = 10;
int32_t beginOffset = appendTo.length();
NumberFormat *currentNumberFormat;
UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0);
// if the pattern character is unrecognized, signal an error and dump out
- if (patternCharPtr == NULL)
+ if (patternCharIndex == UDAT_FIELD_COUNT)
{
if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
status = U_INVALID_FORMAT_ERROR;
return;
}
- patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
int32_t value = cal.get(field, status);
if (U_FAILURE(status)) {
//----------------------------------------------------------------------
-/**
- * Format characters that indicate numeric fields. The character
- * at index 0 is treated specially.
- */
-static const UChar NUMERIC_FORMAT_CHARS[] = {0x4D, 0x59, 0x79, 0x75, 0x64, 0x65, 0x68, 0x48, 0x6D, 0x73, 0x53, 0x44, 0x46, 0x77, 0x57, 0x6B, 0x4B, 0x00}; /* "MYyudehHmsSDFwWkK" */
-
/**
* Return true if the given format character, occuring count
* times, represents a numeric field.
*/
UBool SimpleDateFormat::isNumeric(UChar formatChar, int32_t count) {
- UnicodeString s(NUMERIC_FORMAT_CHARS);
- int32_t i = s.indexOf(formatChar);
- return (i > 0 || (i == 0 && count < 3));
+ return DateFormatSymbols::isNumericPatternChar(formatChar, count);
+}
+
+UBool
+SimpleDateFormat::isAtNumericField(const UnicodeString &pattern, int32_t patternOffset) {
+ if (patternOffset >= pattern.length()) {
+ // not at any field
+ return FALSE;
+ }
+ UChar ch = pattern.charAt(patternOffset);
+ UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);
+ if (f == UDAT_FIELD_COUNT) {
+ // not at any field
+ return FALSE;
+ }
+ int32_t i = patternOffset;
+ while (pattern.charAt(++i) == ch) {}
+ return DateFormatSymbols::isNumericField(f, i - patternOffset);
+}
+
+UBool
+SimpleDateFormat::isAfterNonNumericField(const UnicodeString &pattern, int32_t patternOffset) {
+ if (patternOffset <= 0) {
+ // not after any field
+ return FALSE;
+ }
+ UChar ch = pattern.charAt(--patternOffset);
+ UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);
+ if (f == UDAT_FIELD_COUNT) {
+ // not after any field
+ return FALSE;
+ }
+ int32_t i = patternOffset;
+ while (pattern.charAt(--i) == ch) {}
+ return !DateFormatSymbols::isNumericField(f, patternOffset - i);
}
void
int32_t abutPass = 0;
UBool inQuote = FALSE;
- const UnicodeString numericFormatChars(NUMERIC_FORMAT_CHARS);
MessageFormat * numericLeapMonthFormatter = NULL;
Calendar* calClone = NULL;
if (isNumeric(ch, count)) {
if (abutPat < 0) {
- // Determine if there is an abutting numeric field. For
- // most fields we can just look at the next characters,
- // but the 'm' field is either numeric or text,
- // depending on the count, so we have to look ahead for
- // that field.
- if ((i+1)<fPattern.length()) {
- UBool abutting;
- UChar nextCh = fPattern.charAt(i+1);
- int32_t k = numericFormatChars.indexOf(nextCh);
- if (k == 0) {
- int32_t j = i+2;
- while (j<fPattern.length() &&
- fPattern.charAt(j) == nextCh) {
- ++j;
- }
- abutting = (j-i) < 4; // nextCount < 3
- } else {
- abutting = k > 0;
- }
-
- // Record the start of a set of abutting numeric
- // fields.
- if (abutting) {
- abutPat = fieldPat;
- abutStart = pos;
- abutPass = 0;
- }
+ // Determine if there is an abutting numeric field.
+ // Record the start of a set of abutting numeric fields.
+ if (isAtNumericField(fPattern, i + 1)) {
+ abutPat = fieldPat;
+ abutStart = pos;
+ abutPass = 0;
}
}
} else {
}
}
+ // Special hack for trailing "." after non-numeric field.
+ if (text.charAt(pos) == 0x2e && lenient) {
+ // only do if the last field is not numeric
+ if (isAfterNonNumericField(fPattern, fPattern.length())) {
+ pos++; // skip the extra "."
+ }
+ }
+
// At this point the fields of Calendar have been set. Calendar
// will fill in default values for missing fields when the time
// is computed.
}
//----------------------------------------------------------------------
+static UBool
+newBestMatchWithOptionalDot(const UnicodeString &lcaseText,
+ const UnicodeString &data,
+ UnicodeString &bestMatchName,
+ int32_t &bestMatchLength);
+
int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
int32_t start,
UCalendarDateFields field,
// We keep track of the longest match, and return that. Note that this
// unfortunately requires us to test all array elements.
int32_t bestMatchLength = 0, bestMatch = -1;
+ UnicodeString bestMatchName;
// {sfb} kludge to support case-insensitive comparison
// {markus 2002oct11} do not just use caseCompareBetween because we do not know
// {alan 20040607} don't case change the whole string, since the length
// can change
// TODO we need a case-insensitive startsWith function
- UnicodeString lcase, lcaseText;
+ UnicodeString lcaseText;
text.extract(start, INT32_MAX, lcaseText);
lcaseText.foldCase();
// Always compare if we have no match yet; otherwise only compare
// against potentially better matches (longer strings).
- lcase.fastCopyFrom(data[i]).foldCase();
- int32_t length = lcase.length();
-
- if (length > bestMatchLength &&
- lcaseText.compareBetween(0, length, lcase, 0, length) == 0)
- {
+ if (newBestMatchWithOptionalDot(lcaseText, data[i], bestMatchName, bestMatchLength)) {
bestMatch = i;
- bestMatchLength = length;
}
}
if (bestMatch >= 0)
// Once we have a match, we have to determine the length of the
// original source string. This will usually be == the length of
// the case folded string, but it may differ (e.g. sharp s).
- lcase.fastCopyFrom(data[bestMatch]).foldCase();
// Most of the time, the length will be the same as the length
// of the string from the locale data. Sometimes it will be
// adding a character at a time, until we have a match. We do
// this all in one loop, where we try 'len' first (at index
// i==0).
- int32_t len = data[bestMatch].length(); // 99+% of the time
+ int32_t len = bestMatchName.length(); // 99+% of the time
int32_t n = text.length() - start;
for (i=0; i<=n; ++i) {
int32_t j=i;
}
text.extract(start, j, lcaseText);
lcaseText.foldCase();
- if (lcase == lcaseText) {
+ if (bestMatchName == lcaseText) {
return start + j;
}
}
}
}
- for (p = 0; p < literal.length() && t < text.length(); p += 1, t += 1) {
+ for (p = 0; p < literal.length() && t < text.length();) {
UBool needWhitespace = FALSE;
while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) {
// Ran out of text, or found a non-matching character:
// OK in lenient mode, an error in strict mode.
if (lenient) {
+ if (t == textOffset && text.charAt(t) == 0x2e &&
+ isAfterNonNumericField(pattern, patternOffset)) {
+ // Lenient mode and the literal input text begins with a "." and
+ // we are after a non-numeric field: We skip the "."
+ ++t;
+ continue; // Do not update p.
+ }
break;
}
return FALSE;
}
+ ++p;
+ ++t;
}
// At this point if we're in strict mode we have a complete match.
// no match. Pretend it matched a run of whitespace
// and ignorables in the text.
const UnicodeSet *ignorables = NULL;
- UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), pattern.charAt(i));
-
- if (patternCharPtr != NULL) {
- UDateFormatField patternCharIndex = (UDateFormatField) (patternCharPtr - DateFormatSymbols::getPatternUChars());
-
+ UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(pattern.charAt(i));
+ if (patternCharIndex != UDAT_FIELD_COUNT) {
ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex);
}
// {alan 20040607} don't case change the whole string, since the length
// can change
// TODO we need a case-insensitive startsWith function
- UnicodeString lcase, lcaseText;
+ UnicodeString lcaseText;
text.extract(start, INT32_MAX, lcaseText);
lcaseText.foldCase();
// Always compare if we have no match yet; otherwise only compare
// against potentially better matches (longer strings).
- lcase.fastCopyFrom(data[i]).foldCase();
- int32_t length = lcase.length();
-
- if (length > bestMatchLength &&
- lcaseText.compareBetween(0, length, lcase, 0, length) == 0)
- {
+ if (newBestMatchWithOptionalDot(lcaseText, data[i], bestMatchName, bestMatchLength)) {
bestMatch = i;
- bestMatchLength = length;
- bestMatchName.setTo(data[i]);
isLeapMonth = 0;
}
Formattable monthName((const UnicodeString&)(data[i]));
MessageFormat::format(*monthPattern, &monthName, 1, leapMonthName, status);
if (U_SUCCESS(status)) {
- lcase.fastCopyFrom(leapMonthName).foldCase();
- length = lcase.length();
-
- if (length > bestMatchLength &&
- lcaseText.compareBetween(0, length, lcase, 0, length) == 0)
- {
+ if (newBestMatchWithOptionalDot(lcaseText, leapMonthName, bestMatchName, bestMatchLength)) {
bestMatch = i;
- bestMatchLength = length;
- bestMatchName.setTo(leapMonthName);
isLeapMonth = 1;
}
}
// Once we have a match, we have to determine the length of the
// original source string. This will usually be == the length of
// the case folded string, but it may differ (e.g. sharp s).
- lcase.fastCopyFrom(bestMatchName).foldCase();
// Most of the time, the length will be the same as the length
// of the string from the locale data. Sometimes it will be
}
text.extract(start, j, lcaseText);
lcaseText.foldCase();
- if (lcase == lcaseText) {
+ if (bestMatchName == lcaseText) {
return start + j;
}
}
return -start;
}
+static UBool
+newBestMatchWithOptionalDot(const UnicodeString &lcaseText,
+ const UnicodeString &data,
+ UnicodeString &bestMatchName,
+ int32_t &bestMatchLength) {
+ UnicodeString lcase;
+ lcase.fastCopyFrom(data).foldCase();
+ int32_t length = lcase.length();
+ if (length <= bestMatchLength) {
+ // data cannot provide a better match.
+ return FALSE;
+ }
+
+ if (lcaseText.compareBetween(0, length, lcase, 0, length) == 0) {
+ // normal match
+ bestMatchName = lcase;
+ bestMatchLength = length;
+ return TRUE;
+ }
+ if (lcase.charAt(--length) == 0x2e) {
+ if (lcaseText.compareBetween(0, length, lcase, 0, length) == 0) {
+ // The input text matches the data except for data's trailing dot.
+ bestMatchName = lcase;
+ bestMatchName.truncate(length);
+ bestMatchLength = length;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
//----------------------------------------------------------------------
void
int32_t i;
int32_t ps = 0;
ParsePosition pos(0);
- UDateFormatField patternCharIndex;
+ UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
NumberFormat *currentNumberFormat;
UnicodeString temp;
- UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
UBool lenient = isLenient();
UBool gotNumber = FALSE;
//fprintf(stderr, "%s:%d - [%c] st=%d \n", __FILE__, __LINE__, (char) ch, start);
#endif
- if (patternCharPtr == NULL) {
+ if (patternCharIndex == UDAT_FIELD_COUNT) {
return -start;
}
- patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
UnicodeString hebr("hebr", 4, US_INV);