/** * If in "by digits" mode, fills in the substitution one decimal digit * at a time using the rule set containing this substitution. * Otherwise, uses the superclass function. * @param number The number being formatted * @param toInsertInto The string to insert the result of formatting * the substitution into * @param pos The position of the owning rule's rule text in * toInsertInto */ void FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const { // if we're not in "byDigits" mode, just use the inherited // doSubstitution() routine if (!byDigits) { NFSubstitution::doSubstitution(number, toInsertInto, _pos); // if we're in "byDigits" mode, transform the value into an integer // by moving the decimal point eight places to the right and // pulling digits off the right one at a time, formatting each digit // as an integer using this substitution's owning rule set // (this is slower, but more accurate, than doing it from the // other end) } else { // int32_t numberToFormat = (int32_t)uprv_round(transformNumber(number) * uprv_pow(10, kMaxDecimalDigits)); // // this flag keeps us from formatting trailing zeros. It starts // // out false because we're pulling from the right, and switches // // to true the first time we encounter a non-zero digit // UBool doZeros = FALSE; // for (int32_t i = 0; i < kMaxDecimalDigits; i++) { // int64_t digit = numberToFormat % 10; // if (digit != 0 || doZeros) { // if (doZeros && useSpaces) { // toInsertInto.insert(_pos + getPos(), gSpace); // } // doZeros = TRUE; // getRuleSet()->format(digit, toInsertInto, _pos + getPos()); // } // numberToFormat /= 10; // } DigitList dl; dl.set(number); dl.roundFixedPoint(20); // round to 20 fraction digits. dl.reduce(); // Removes any trailing zeros. UBool pad = FALSE; for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) { // Loop iterates over fraction digits, starting with the LSD. // include both real digits from the number, and zeros // to the left of the MSD but to the right of the decimal point. if (pad && useSpaces) { toInsertInto.insert(_pos + getPos(), gSpace); } else { pad = TRUE; } int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0; getRuleSet()->format(digit, toInsertInto, _pos + getPos()); } if (!pad) { // hack around lack of precision in digitlist. if we would end up with // "foo point" make sure we add a " zero" to the end. getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos()); } } }
UBool FractionalPartSubstitution::doParse(const UnicodeString& text, ParsePosition& parsePosition, double baseValue, double /*upperBound*/, UBool lenientParse, Formattable& resVal) const { // if we're not in byDigits mode, we can just use the inherited // doParse() if (!byDigits) { return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, resVal); // if we ARE in byDigits mode, parse the text one digit at a time // using this substitution's owning rule set (we do this by setting // upperBound to 10 when calling doParse() ) until we reach // nonmatching text } else { UnicodeString workText(text); ParsePosition workPos(1); double result = 0; int32_t digit; // double p10 = 0.1; DigitList dl; NumberFormat* fmt = NULL; while (workText.length() > 0 && workPos.getIndex() != 0) { workPos.setIndex(0); Formattable temp; getRuleSet()->parse(workText, workPos, 10, temp); UErrorCode status = U_ZERO_ERROR; digit = temp.getLong(status); // digit = temp.getType() == Formattable::kLong ? // temp.getLong() : // (int32_t)temp.getDouble(); if (lenientParse && workPos.getIndex() == 0) { if (!fmt) { status = U_ZERO_ERROR; fmt = NumberFormat::createInstance(status); if (U_FAILURE(status)) { delete fmt; fmt = NULL; } } if (fmt) { fmt->parse(workText, temp, workPos); digit = temp.getLong(status); } } if (workPos.getIndex() != 0) { dl.append((char)('0' + digit)); // result += digit * p10; // p10 /= 10; parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex()); workText.removeBetween(0, workPos.getIndex()); while (workText.length() > 0 && workText.charAt(0) == gSpace) { workText.removeBetween(0, 1); parsePosition.setIndex(parsePosition.getIndex() + 1); } } } delete fmt; result = dl.getCount() == 0 ? 0 : dl.getDouble(); result = composeRuleValue(result, baseValue); resVal.setDouble(result); return TRUE; } }