- // process digits or Inf, find decimal position
- const UnicodeString *inf = &fImpl->getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
- int32_t infLen = (text.compare(position, inf->length(), *inf)
- ? 0 : inf->length());
- position += infLen; // infLen is non-zero when it does equal to infinity
- status[fgStatusInfinite] = infLen != 0;
-
- if (infLen != 0) {
- parsedNum.append("Infinity", err);
- } else {
- // We now have a string of digits, possibly with grouping symbols,
- // and decimal points. We want to process these into a DigitList.
- // We don't want to put a bunch of leading zeros into the DigitList
- // though, so we keep track of the location of the decimal point,
- // put only significant digits into the DigitList, and adjust the
- // exponent as needed.
-
-
- UBool strictFail = FALSE; // did we exit with a strict parse failure?
- int32_t lastGroup = -1; // where did we last see a grouping separator?
- int32_t digitStart = position;
- int32_t gs2 = fImpl->fEffGrouping.fGrouping2 == 0 ? fImpl->fEffGrouping.fGrouping : fImpl->fEffGrouping.fGrouping2;
-
- const UnicodeString *decimalString;
- if (fImpl->fMonetary) {
- decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
- } else {
- decimalString = &fImpl->getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
- }
- UChar32 decimalChar = decimalString->char32At(0);
- int32_t decimalStringLength = decimalString->length();
- int32_t decimalCharLength = U16_LENGTH(decimalChar);
-
- UBool sawDecimal = FALSE;
- UChar32 sawDecimalChar = 0xFFFF;
- UBool sawGrouping = FALSE;
- UChar32 sawGroupingChar = 0xFFFF;
- UBool sawDigit = FALSE;
- int32_t backup = -1;
- int32_t digit;
-
- // equivalent grouping and decimal support
- const UnicodeSet *decimalSet = NULL;
- const UnicodeSet *groupingSet = NULL;
-
- if (decimalCharLength == decimalStringLength) {
- decimalSet = DecimalFormatStaticSets::getSimilarDecimals(decimalChar, strictParse);
- }
-
- if (groupingCharLength == groupingStringLength) {
- if (strictParse) {
- groupingSet = fStaticSets->fStrictDefaultGroupingSeparators;
- } else {
- groupingSet = fStaticSets->fDefaultGroupingSeparators;
- }
- }
-
- // We need to test groupingChar and decimalChar separately from groupingSet and decimalSet, if the sets are even initialized.
- // If sawDecimal is TRUE, only consider sawDecimalChar and NOT decimalSet
- // If a character matches decimalSet, don't consider it to be a member of the groupingSet.
-
- // We have to track digitCount ourselves, because digits.fCount will
- // pin when the maximum allowable digits is reached.
- int32_t digitCount = 0;
- int32_t integerDigitCount = 0;
-
- for (; position < textLength; )
- {
- UChar32 ch = text.char32At(position);
-
- /* We recognize all digit ranges, not only the Latin digit range
- * '0'..'9'. We do so by using the Character.digit() method,
- * which converts a valid Unicode digit to the range 0..9.
- *
- * The character 'ch' may be a digit. If so, place its value
- * from 0 to 9 in 'digit'. First try using the locale digit,
- * which may or MAY NOT be a standard Unicode digit range. If
- * this fails, try using the standard Unicode digit ranges by
- * calling Character.digit(). If this also fails, digit will
- * have a value outside the range 0..9.
- */
- digit = ch - zero;
- if (digit < 0 || digit > 9)
- {
- digit = u_charDigitValue(ch);
- }
-
- // As a last resort, look through the localized digits if the zero digit
- // is not a "standard" Unicode digit.
- if ( (digit < 0 || digit > 9) && u_charDigitValue(zero) != 0) {
- digit = 0;
- // Already check above (digit = ch - zero) for ch==zero; the only check we need to do here is:
- // if \u3007 is treated as 0 for parsing, \u96F6 should be too. Otherwise check for nonzero digits.
- if ( zero!=0x3007 || ch!=0x96F6 ) {
- for (digit = 1 ; digit < 10 ; digit++ ) {
- if ( fImpl->getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kOneDigitSymbol+digit-1)).char32At(0) == ch ) {
- break;
- }
- }
- }
- }
-
- if (digit >= 0 && digit <= 9)
- {
- if (strictParse && backup != -1) {
- // comma followed by digit, so group before comma is a
- // secondary group. If there was a group separator
- // before that, the group must == the secondary group
- // length, else it can be <= the the secondary group
- // length.
- if ((lastGroup != -1 && backup - lastGroup - 1 != gs2) ||
- (lastGroup == -1 && position - digitStart - 1 > gs2)) {
- strictFail = TRUE;
- break;
- }
-
- lastGroup = backup;
- }
-
- // Cancel out backup setting (see grouping handler below)
- backup = -1;
- sawDigit = TRUE;
-
- // Note: this will append leading zeros
- parsedNum.append((char)(digit + '0'), err);
-
- // count any digit that's not a leading zero
- if (digit > 0 || digitCount > 0 || sawDecimal) {
- digitCount += 1;
-
- // count any integer digit that's not a leading zero
- if (! sawDecimal) {
- integerDigitCount += 1;
- }
- }
-
- position += U16_LENGTH(ch);
- }
- else if (groupingStringLength > 0 &&
- matchGrouping(groupingChar, sawGrouping, sawGroupingChar, groupingSet,
- decimalChar, decimalSet,
- ch) && groupingUsed)
- {
- if (sawDecimal) {
- break;
- }
-
- if (strictParse) {
- if ( (!sawDigit && groupingSet!=NULL && u_isWhitespace(ch)) || backup != -1 ) {
- // We differ from the ICU4J code by allowing a leading group sep in strict mode (for
- // backward compatibility) as long as it is not one of the breaking whitespace characters
- // that is only treated as a group separator because of the equivalence set. If we get
- // here it is because the leading sep was such a breaking space, or there were multiple
- // group separators in a row. Note that the DecimalFormat documentation says
- // "During parsing, grouping separators are ignored" and that was for strict parsing,
- // so we may need to further revisit this strictParse restriction to ensure compatibility.
- // Also note: u_isWhitespace is true for all Zs/Zl/Zp except the no-break ones: 00A0,2007,202F.
- // In CLDR, all locales that have space as a group separator use 00A0 (NBSP).
- strictFail = TRUE;
- break;
- }
- }
-
- // Ignore grouping characters, if we are using them, but require
- // that they be followed by a digit. Otherwise we backup and
- // reprocess them.
- backup = position;
- position += groupingStringLength;
- sawGrouping=TRUE;
- // Once we see a grouping character, we only accept that grouping character from then on.
- sawGroupingChar=ch;
- }
- else if (matchDecimal(decimalChar,sawDecimal,sawDecimalChar, decimalSet, ch))
- {
- if (strictParse) {
- if (backup != -1 ||
- (lastGroup != -1 && position - lastGroup != fImpl->fEffGrouping.fGrouping + 1)) {
- strictFail = TRUE;
- break;
- }
- }
-
- // If we're only parsing integers, or if we ALREADY saw the
- // decimal, then don't parse this one.
- if (isParseIntegerOnly() || sawDecimal) {
- break;
- }
-
- parsedNum.append('.', err);
- position += decimalStringLength;
- sawDecimal = TRUE;
- // Once we see a decimal character, we only accept that decimal character from then on.
- sawDecimalChar=ch;
- // decimalSet is considered to consist of (ch,ch)
- }
- else {
-
- if(!fBoolFlags.contains(UNUM_PARSE_NO_EXPONENT) || // don't parse if this is set unless..
- isScientificNotation()) { // .. it's an exponent format - ignore setting and parse anyways
- const UnicodeString *tmp;
- tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
- // TODO: CASE
- if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT)) // error code is set below if !sawDigit
- {
- // Parse sign, if present
- int32_t pos = position + tmp->length();
- char exponentSign = '+';
-
- if (pos < textLength)
- {
- tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
- if (!text.compare(pos, tmp->length(), *tmp))
- {
- pos += tmp->length();
- }
- else {
- tmp = &fImpl->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
- if (!text.compare(pos, tmp->length(), *tmp))
- {
- exponentSign = '-';
- pos += tmp->length();
- }
- }
- }
-
- UBool sawExponentDigit = FALSE;
- while (pos < textLength) {
- ch = text[(int32_t)pos];
- digit = ch - zero;
-
- if (digit < 0 || digit > 9) {
- digit = u_charDigitValue(ch);
- }
- if (0 <= digit && digit <= 9) {
- if (!sawExponentDigit) {
- parsedNum.append('E', err);
- parsedNum.append(exponentSign, err);
- sawExponentDigit = TRUE;
- }
- ++pos;
- parsedNum.append((char)(digit + '0'), err);
- } else {
- break;
- }
- }
-
- if (sawExponentDigit) {
- position = pos; // Advance past the exponent
- }
-
- break; // Whether we fail or succeed, we exit this loop
- } else {
- break;
- }
- } else { // not parsing exponent
- break;
- }
- }
- }
-
- // if we didn't see a decimal and it is required, check to see if the pattern had one
- if(!sawDecimal && isDecimalPatternMatchRequired())
- {
- if(formatPattern.indexOf(kPatternDecimalSeparator) != -1)
- {
- parsePosition.setIndex(oldStart);
- parsePosition.setErrorIndex(position);
- debug("decimal point match required fail!");
- return FALSE;
- }
- }
-
- if (backup != -1)
- {
- position = backup;
- }
-
- if (strictParse && !sawDecimal) {
- if (lastGroup != -1 && position - lastGroup != fImpl->fEffGrouping.fGrouping + 1) {
- strictFail = TRUE;
- }
- }