com.ibm.icu.impl.number.parse.ParsedNumber Maven / Gradle / Ivy
Show all versions of icu4j Show documentation
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.impl.number.parse;
import java.util.Comparator;
import com.ibm.icu.impl.StringSegment;
import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
/**
* Struct-like class to hold the results of a parsing routine.
*
* @author sffc
*/
public class ParsedNumber {
/**
* The numerical value that was parsed.
*/
public DecimalQuantity_DualStorageBCD quantity;
/**
* The index of the last char consumed during parsing. If parsing started at index 0, this is equal
* to the number of chars consumed. This is NOT necessarily the same as the StringSegment offset;
* "weak" chars, like whitespace, change the offset, but the charsConsumed is not touched until a
* "strong" char is encountered.
*/
public int charEnd;
/**
* Boolean flags (see constants below).
*/
public int flags;
/**
* The pattern string corresponding to the prefix that got consumed.
*/
public String prefix;
/**
* The pattern string corresponding to the suffix that got consumed.
*/
public String suffix;
/**
* The currency that got consumed.
*/
public String currencyCode;
public static final int FLAG_NEGATIVE = 0x0001;
public static final int FLAG_PERCENT = 0x0002;
public static final int FLAG_PERMILLE = 0x0004;
public static final int FLAG_HAS_EXPONENT = 0x0008;
// public static final int FLAG_HAS_DEFAULT_CURRENCY = 0x0010; // no longer used
public static final int FLAG_HAS_DECIMAL_SEPARATOR = 0x0020;
public static final int FLAG_NAN = 0x0040;
public static final int FLAG_INFINITY = 0x0080;
public static final int FLAG_FAIL = 0x0100;
/** A Comparator that favors ParsedNumbers with the most chars consumed. */
public static final Comparator COMPARATOR = new Comparator() {
@Override
public int compare(ParsedNumber o1, ParsedNumber o2) {
return o1.charEnd - o2.charEnd;
}
};
public ParsedNumber() {
clear();
}
/**
* Clears the data from this ParsedNumber, in effect failing the current parse.
*/
public void clear() {
quantity = null;
charEnd = 0;
flags = 0;
prefix = null;
suffix = null;
currencyCode = null;
}
public void copyFrom(ParsedNumber other) {
quantity = other.quantity == null ? null
: (DecimalQuantity_DualStorageBCD) other.quantity.createCopy();
charEnd = other.charEnd;
flags = other.flags;
prefix = other.prefix;
suffix = other.suffix;
currencyCode = other.currencyCode;
}
/**
* Call this method to register that a "strong" char was consumed. This should be done after calling
* {@link StringSegment#setOffset} or {@link StringSegment#adjustOffset} except when the char is
* "weak", like whitespace.
*
*
* What is a strong versus weak char? The behavior of number parsing is to "stop"
* after reading the number, even if there is other content following the number. For example, after
* parsing the string "123 " (123 followed by a space), the cursor should be set to 3, not 4, even
* though there are matchers that accept whitespace. In this example, the digits are strong, whereas
* the whitespace is weak. Grouping separators are weak, whereas decimal separators are strong. Most
* other chars are strong.
*
* @param segment
* The current StringSegment, usually immediately following a call to setOffset.
*/
public void setCharsConsumed(StringSegment segment) {
charEnd = segment.getOffset();
}
/** Apply certain number-related flags to the DecimalQuantity. */
public void postProcess() {
if (quantity != null && 0 != (flags & FLAG_NEGATIVE)) {
quantity.negate();
}
}
/**
* Returns whether this the parse was successful. To be successful, at least one char must have been
* consumed, and the failure flag must not be set.
*/
public boolean success() {
return charEnd > 0 && 0 == (flags & FLAG_FAIL);
}
public boolean seenNumber() {
return quantity != null || 0 != (flags & FLAG_NAN) || 0 != (flags & FLAG_INFINITY);
}
public Number getNumber() {
return getNumber(0);
}
/** @param parseFlags Configuration settings from ParsingUtils.java */
public Number getNumber(int parseFlags) {
boolean sawNaN = 0 != (flags & FLAG_NAN);
boolean sawInfinity = 0 != (flags & FLAG_INFINITY);
boolean forceBigDecimal = 0 != (parseFlags & ParsingUtils.PARSE_FLAG_FORCE_BIG_DECIMAL);
boolean integerOnly = 0 != (parseFlags & ParsingUtils.PARSE_FLAG_INTEGER_ONLY);
// Check for NaN, infinity, and -0.0
if (sawNaN) {
return Double.NaN;
}
if (sawInfinity) {
if (0 != (flags & FLAG_NEGATIVE)) {
return Double.NEGATIVE_INFINITY;
} else {
return Double.POSITIVE_INFINITY;
}
}
assert quantity != null;
if (quantity.isZeroish() && quantity.isNegative() && !integerOnly) {
return -0.0;
}
if (quantity.fitsInLong() && !forceBigDecimal) {
return quantity.toLong(false);
} else {
return quantity.toBigDecimal();
}
}
boolean isBetterThan(ParsedNumber other) {
return COMPARATOR.compare(this, other) > 0;
}
}