示例#1
0
void ParsedNumber::populateFormattable(Formattable& output, parse_flags_t parseFlags) const {
    bool sawNaN = 0 != (flags & FLAG_NAN);
    bool sawInfinity = 0 != (flags & FLAG_INFINITY);
    bool integerOnly = 0 != (parseFlags & PARSE_FLAG_INTEGER_ONLY);

    // Check for NaN, infinity, and -0.0
    if (sawNaN) {
        // Can't use NAN or std::nan because the byte pattern is platform-dependent;
        // MSVC sets the sign bit, but Clang and GCC do not
        output.setDouble(uprv_getNaN());
        return;
    }
    if (sawInfinity) {
        if (0 != (flags & FLAG_NEGATIVE)) {
            output.setDouble(-INFINITY);
            return;
        } else {
            output.setDouble(INFINITY);
            return;
        }
    }
    U_ASSERT(!quantity.bogus);
    if (quantity.isZero() && quantity.isNegative() && !integerOnly) {
        output.setDouble(-0.0);
        return;
    }

    // All other numbers
    output.adoptDecimalQuantity(new DecimalQuantity(quantity));
}
/**
 * If this is a >>> substitution, match only against ruleToUse.
 * Otherwise, use the superclass function.
 * @param text The string to parse
 * @param parsePosition Ignored on entry, updated on exit to point to
 * the first unmatched character.
 * @param baseValue The partial parse result prior to calling this
 * routine.
 */
UBool
ModulusSubstitution::doParse(const UnicodeString& text,
                             ParsePosition& parsePosition,
                             double baseValue,
                             double upperBound,
                             UBool lenientParse,
                             Formattable& result) const
{
    // if this isn't a >>> substitution, we can just use the
    // inherited parse() routine to do the parsing
    if (ruleToUse == NULL) {
        return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, lenientParse, result);

        // but if it IS a >>> substitution, we have to do it here: we
        // use the specific rule's doParse() method, and then we have to
        // do some of the other work of NFRuleSet.parse()
    } else {
        ruleToUse->doParse(text, parsePosition, FALSE, upperBound, result);

        if (parsePosition.getIndex() != 0) {
            UErrorCode status = U_ZERO_ERROR;
            double tempResult = result.getDouble(status);
            tempResult = composeRuleValue(tempResult, baseValue);
            result.setDouble(tempResult);
        }

        return TRUE;
    }
}
示例#3
0
void
ChoiceFormat::parse(const UnicodeString& text, 
                    Formattable& result,
                    ParsePosition& status) const
{
    // find the best number (defined as the one with the longest parse)
    int32_t start = status.getIndex();
    int32_t furthest = start;
    double bestNumber = uprv_getNaN();
    double tempNumber = 0.0;
    for (int i = 0; i < fCount; ++i) {
        int32_t len = fChoiceFormats[i].length();
        if (text.compare(start, len, fChoiceFormats[i]) == 0) {
            status.setIndex(start + len);
            tempNumber = fChoiceLimits[i];
            if (status.getIndex() > furthest) {
                furthest = status.getIndex();
                bestNumber = tempNumber;
                if (furthest == text.length()) 
                    break;
            }
        }
    }
    status.setIndex(furthest);
    if (status.getIndex() == start) {
        status.setErrorIndex(furthest);
    }
    result.setDouble(bestNumber);
}
 virtual UBool doParse(const UnicodeString& /*text*/,
     ParsePosition& /*parsePosition*/, 
     double baseValue,
     double /*upperBound*/,
     UBool /*lenientParse*/,
     Formattable& result) const
 { result.setDouble(baseValue); return TRUE; }
示例#5
0
void
ChoiceFormat::parse(const UnicodeString& text,
                    Formattable& result,
                    ParsePosition& pos) const
{
    result.setDouble(parseArgument(msgPattern, 0, text, pos));
}
/**
 * Parses a string using the rule set or DecimalFormat belonging
 * to this substitution.  If there's a match, a mathematical
 * operation (the inverse of the one used in formatting) is
 * performed on the result of the parse and the value passed in
 * and returned as the result.  The parse position is updated to
 * point to the first unmatched character in the string.
 * @param text The string to parse
 * @param parsePosition On entry, ignored, but assumed to be 0.
 * On exit, this is updated to point to the first unmatched
 * character (or 0 if the substitution didn't match)
 * @param baseValue A partial parse result that should be
 * combined with the result of this parse
 * @param upperBound When searching the rule set for a rule
 * matching the string passed in, only rules with base values
 * lower than this are considered
 * @param lenientParse If true and matching against rules fails,
 * the substitution will also try matching the text against
 * numerals using a default-costructed NumberFormat.  If false,
 * no extra work is done.  (This value is false whenever the
 * formatter isn't in lenient-parse mode, but is also false
 * under some conditions even when the formatter _is_ in
 * lenient-parse mode.)
 * @return If there's a match, this is the result of composing
 * baseValue with whatever was returned from matching the
 * characters.  This will be either a Long or a Double.  If there's
 * no match this is new Long(0) (not null), and parsePosition
 * is left unchanged.
 */
UBool
NFSubstitution::doParse(const UnicodeString& text,
                        ParsePosition& parsePosition,
                        double baseValue,
                        double upperBound,
                        UBool lenientParse,
                        Formattable& result) const
{
#ifdef RBNF_DEBUG
    fprintf(stderr, "<nfsubs> %x bv: %g ub: %g\n", this, baseValue, upperBound);
#endif
    // figure out the highest base value a rule can have and match
    // the text being parsed (this varies according to the type of
    // substitutions: multiplier, modulus, and numerator substitutions
    // restrict the search to rules with base values lower than their
    // own; same-value substitutions leave the upper bound wherever
    // it was, and the others allow any rule to match
    upperBound = calcUpperBound(upperBound);

    // use our rule set to parse the text.  If that fails and
    // lenient parsing is enabled (this is always false if the
    // formatter's lenient-parsing mode is off, but it may also
    // be false even when the formatter's lenient-parse mode is
    // on), then also try parsing the text using a default-
    // constructed NumberFormat
    if (ruleSet != NULL) {
        ruleSet->parse(text, parsePosition, upperBound, result);
        if (lenientParse && !ruleSet->isFractionRuleSet() && parsePosition.getIndex() == 0) {
            UErrorCode status = U_ZERO_ERROR;
            NumberFormat* fmt = NumberFormat::createInstance(status);
            if (U_SUCCESS(status)) {
                fmt->parse(text, result, parsePosition);
            }
            delete fmt;
        }

        // ...or use our DecimalFormat to parse the text
    } else if (numberFormat != NULL) {
        numberFormat->parse(text, result, parsePosition);
    }

    // if the parse was successful, we've already advanced the caller's
    // parse position (this is the one function that doesn't have one
    // of its own).  Derive a parse result and return it as a Long,
    // if possible, or a Double
    if (parsePosition.getIndex() != 0) {
        UErrorCode status = U_ZERO_ERROR;
        double tempResult = result.getDouble(status);

        // composeRuleValue() produces a full parse result from
        // the partial parse result passed to this function from
        // the caller (this is either the owning rule's base value
        // or the partial result obtained from composing the
        // owning rule's base value with its other substitution's
        // parse result) and the partial parse result obtained by
        // matching the substitution (which will be the same value
        // the caller would get by parsing just this part of the
        // text with RuleBasedNumberFormat.parse() ).  How the two
        // values are used to derive the full parse result depends
        // on the types of substitutions: For a regular rule, the
        // ultimate result is its multiplier substitution's result
        // times the rule's divisor (or the rule's base value) plus
        // the modulus substitution's result (which will actually
        // supersede part of the rule's base value).  For a negative-
        // number rule, the result is the negative of its substitution's
        // result.  For a fraction rule, it's the sum of its two
        // substitution results.  For a rule in a fraction rule set,
        // it's the numerator substitution's result divided by
        // the rule's base value.  Results from same-value substitutions
        // propagate back upard, and null substitutions don't affect
        // the result.
        tempResult = composeRuleValue(tempResult, baseValue);
        result.setDouble(tempResult);
        return TRUE;
        // if the parse was UNsuccessful, return 0
    } else {
        result.setLong(0);
        return FALSE;
    }
}
UBool 
NumeratorSubstitution::doParse(const UnicodeString& text, 
                               ParsePosition& parsePosition,
                               double baseValue,
                               double upperBound,
                               UBool /*lenientParse*/,
                               Formattable& result) const
{
    // we don't have to do anything special to do the parsing here,
    // but we have to turn lenient parsing off-- if we leave it on,
    // it SERIOUSLY messes up the algorithm

    // if withZeros is true, we need to count the zeros
    // and use that to adjust the parse result
    UErrorCode status = U_ZERO_ERROR;
    int32_t zeroCount = 0;
    UnicodeString workText(text);

    if (withZeros) {
        ParsePosition workPos(1);
        Formattable temp;

        while (workText.length() > 0 && workPos.getIndex() != 0) {
            workPos.setIndex(0);
            getRuleSet()->parse(workText, workPos, 1, temp); // parse zero or nothing at all
            if (workPos.getIndex() == 0) {
                // we failed, either there were no more zeros, or the number was formatted with digits
                // either way, we're done
                break;
            }

            ++zeroCount;
            parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
            workText.remove(0, workPos.getIndex());
            while (workText.length() > 0 && workText.charAt(0) == gSpace) {
                workText.remove(0, 1);
                parsePosition.setIndex(parsePosition.getIndex() + 1);
            }
        }

        workText = text;
        workText.remove(0, (int32_t)parsePosition.getIndex());
        parsePosition.setIndex(0);
    }

    // we've parsed off the zeros, now let's parse the rest from our current position
    NFSubstitution::doParse(workText, parsePosition, withZeros ? 1 : baseValue, upperBound, FALSE, result);

    if (withZeros) {
        // any base value will do in this case.  is there a way to
        // force this to not bother trying all the base values?

        // compute the 'effective' base and prescale the value down
        int64_t n = result.getLong(status); // force conversion!
        int64_t d = 1;
        int32_t pow = 0;
        while (d <= n) {
            d *= 10;
            ++pow;
        }
        // now add the zeros
        while (zeroCount > 0) {
            d *= 10;
            --zeroCount;
        }
        // d is now our true denominator
        result.setDouble((double)n/(double)d);
    }

    return TRUE;
}
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.fCount == 0 ? 0 : dl.getDouble();
        result = composeRuleValue(result, baseValue);
        resVal.setDouble(result);
        return TRUE;
    }
}