< prev index next >
src/java.base/share/classes/java/text/CompactNumberFormat.java
Print this page
rev 60563 : [mq]: 8251499
@@ -40,11 +40,10 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
* <p>
* {@code CompactNumberFormat} is a concrete subclass of {@code NumberFormat}
@@ -587,16 +586,18 @@
String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart);
String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart);
if (!prefix.isEmpty() || !suffix.isEmpty()) {
appendPrefix(result, prefix, delegate);
+ if (divisor > 0) {
roundedNumber = roundedNumber / divisor;
decimalFormat.setDigitList(roundedNumber, isNegative, getMaximumFractionDigits());
decimalFormat.subformatNumber(result, delegate, isNegative,
false, getMaximumIntegerDigits(), getMinimumIntegerDigits(),
getMaximumFractionDigits(), getMinimumFractionDigits());
appendSuffix(result, suffix, delegate);
+ }
} else {
defaultDecimalFormat.doubleSubformat(number, result, delegate, isNegative);
}
} else {
defaultDecimalFormat.doubleSubformat(number, result, delegate, isNegative);
@@ -653,10 +654,11 @@
int iPart = getIntegerPart(number, divisor);
String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart);
String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart);
if (!prefix.isEmpty() || !suffix.isEmpty()) {
appendPrefix(result, prefix, delegate);
+ if (divisor > 0) {
if ((number % divisor == 0)) {
number = number / divisor;
decimalFormat.setDigitList(number, isNegative, 0);
decimalFormat.subformatNumber(result, delegate,
isNegative, true, getMaximumIntegerDigits(),
@@ -672,10 +674,11 @@
isNegative, false, getMaximumIntegerDigits(),
getMinimumIntegerDigits(), getMaximumFractionDigits(),
getMinimumFractionDigits());
}
appendSuffix(result, suffix, delegate);
+ }
} else {
number = isNegative ? -number : number;
defaultDecimalFormat.format(number, result, delegate);
}
} else {
@@ -746,16 +749,18 @@
int iPart = getIntegerPart(number.doubleValue(), divisor.doubleValue());
String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart);
String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart);
if (!prefix.isEmpty() || !suffix.isEmpty()) {
appendPrefix(result, prefix, delegate);
+ if (divisor.doubleValue() > 0) {
number = number.divide(new BigDecimal(divisor.toString()), getRoundingMode());
decimalFormat.setDigitList(number, isNegative, getMaximumFractionDigits());
decimalFormat.subformatNumber(result, delegate, isNegative,
false, getMaximumIntegerDigits(), getMinimumIntegerDigits(),
getMaximumFractionDigits(), getMinimumFractionDigits());
appendSuffix(result, suffix, delegate);
+ }
} else {
number = isNegative ? number.negate() : number;
defaultDecimalFormat.format(number, result, delegate);
}
} else {
@@ -811,10 +816,11 @@
int iPart = getIntegerPart(number.doubleValue(), divisor.doubleValue());
String prefix = getAffix(false, true, isNegative, compactDataIndex, iPart);
String suffix = getAffix(false, false, isNegative, compactDataIndex, iPart);
if (!prefix.isEmpty() || !suffix.isEmpty()) {
appendPrefix(result, prefix, delegate);
+ if (divisor.doubleValue() > 0) {
if (number.mod(new BigInteger(divisor.toString()))
.compareTo(BigInteger.ZERO) == 0) {
number = number.divide(new BigInteger(divisor.toString()));
decimalFormat.setDigitList(number, isNegative, 0);
@@ -833,10 +839,11 @@
isNegative, false, getMaximumIntegerDigits(),
getMinimumIntegerDigits(), getMaximumFractionDigits(),
getMinimumFractionDigits());
}
appendSuffix(result, suffix, delegate);
+ }
} else {
number = isNegative ? number.negate() : number;
defaultDecimalFormat.format(number, result, delegate, formatLong);
}
} else {
@@ -903,12 +910,11 @@
private void append(StringBuffer result, String string,
FieldDelegate delegate, List<FieldPosition> positions) {
if (!string.isEmpty()) {
int start = result.length();
result.append(string);
- for (int counter = 0; counter < positions.size(); counter++) {
- FieldPosition fp = positions.get(counter);
+ for (FieldPosition fp : positions) {
Format.Field attribute = fp.getFieldAttribute();
delegate.formatted(attribute, attribute,
start + fp.getBeginIndex(),
start + fp.getEndIndex(), result);
}
@@ -1089,47 +1095,55 @@
return delegate.getIterator(sb.toString());
}
/**
* Computes the divisor using minimum integer digits and
- * matched pattern index.
+ * matched pattern index. If minIntDigits is empty, the divisor
+ * will be negated.
* @param minIntDigits string of 0s in compact pattern
* @param patternIndex index of matched compact pattern
* @return divisor value for the number matching the compact
* pattern at given {@code patternIndex}
*/
private Number computeDivisor(String minIntDigits, int patternIndex) {
- int count = minIntDigits.length() - 1;
+ int count = minIntDigits.length();
Number matchedValue;
// The divisor value can go above long range, if the compact patterns
// goes above index 18, divisor may need to be stored as BigInteger,
// since long can't store numbers >= 10^19,
if (patternIndex < 19) {
matchedValue = (long) Math.pow(RANGE_MULTIPLIER, patternIndex);
} else {
matchedValue = BigInteger.valueOf(RANGE_MULTIPLIER).pow(patternIndex);
}
Number divisor = matchedValue;
- if (count != 0) {
+ if (count > 0) {
if (matchedValue instanceof BigInteger) {
BigInteger bigValue = (BigInteger) matchedValue;
- if (bigValue.compareTo(BigInteger.valueOf((long) Math.pow(RANGE_MULTIPLIER, count))) < 0) {
+ if (bigValue.compareTo(BigInteger.valueOf((long) Math.pow(RANGE_MULTIPLIER, count - 1))) < 0) {
throw new IllegalArgumentException("Invalid Pattern"
+ " [" + compactPatterns[patternIndex]
+ "]: min integer digits specified exceeds the limit"
+ " for the index " + patternIndex);
}
- divisor = bigValue.divide(BigInteger.valueOf((long) Math.pow(RANGE_MULTIPLIER, count)));
+ divisor = bigValue.divide(BigInteger.valueOf((long) Math.pow(RANGE_MULTIPLIER, count - 1)));
} else {
long longValue = (long) matchedValue;
- if (longValue < (long) Math.pow(RANGE_MULTIPLIER, count)) {
+ if (longValue < (long) Math.pow(RANGE_MULTIPLIER, count - 1)) {
throw new IllegalArgumentException("Invalid Pattern"
+ " [" + compactPatterns[patternIndex]
+ "]: min integer digits specified exceeds the limit"
+ " for the index " + patternIndex);
}
- divisor = longValue / (long) Math.pow(RANGE_MULTIPLIER, count);
+ divisor = longValue / (long) Math.pow(RANGE_MULTIPLIER, count - 1);
+ }
+ } else {
+ // no '0's. Indicate it by negating the divisor
+ if (divisor instanceof BigInteger) {
+ divisor = ((BigInteger) divisor).negate();
+ } else {
+ divisor = - divisor.longValue();
}
}
return divisor;
}
@@ -1138,11 +1152,11 @@
* series of prefixes, suffixes and their respective divisor
* value.
*
*/
private static final Pattern PLURALS =
- Pattern.compile("^\\{(?<plurals>.*)\\}$");
+ Pattern.compile("^\\{(?<plurals>.*)}$");
private static final Pattern COUNT_PATTERN =
Pattern.compile("(zero|one|two|few|many|other):((' '|[^ ])+)[ ]*");
private void processCompactPatterns() {
int size = compactPatterns.length;
positivePrefixPatterns = new ArrayList<>(size);
@@ -1196,17 +1210,17 @@
throw new IllegalArgumentException(ise);
}
}
// Patterns for plurals syntax validation
- private final static String EXPR = "([niftvw]{1})\\s*(([/\\%])\\s*(\\d+))*";
- private final static String RELATION = "(!{0,1}=)";
+ private final static String EXPR = "([niftvw])\\s*(([/%])\\s*(\\d+))*";
+ private final static String RELATION = "(!?=)";
private final static String VALUE_RANGE = "((\\d+)\\.\\.(\\d+)|\\d+)";
private final static String CONDITION = EXPR + "\\s*" +
RELATION + "\\s*" +
VALUE_RANGE + "\\s*" +
- "(\\,\\s*" + VALUE_RANGE + ")*";
+ "(,\\s*" + VALUE_RANGE + ")*";
private final static Pattern PLURALRULES_PATTERN =
Pattern.compile("(zero|one|two|few|many):\\s*" +
CONDITION +
"(\\s*(and|or)\\s*" + CONDITION + ")*");
@@ -1398,17 +1412,10 @@
negativeSuffix = positiveSuffix;
negativePrefix = "'-" + positivePrefix;
}
}
- // If no 0s are specified in a non empty pattern, it is invalid
- if (!pattern.isEmpty() && zeros.isEmpty()) {
- throw new IllegalArgumentException("Invalid pattern"
- + " [" + pattern + "]: all patterns must include digit"
- + " placement 0s");
- }
-
// Only if positive affix exists; else put empty strings
if (!positivePrefix.isEmpty() || !positiveSuffix.isEmpty()) {
positivePrefixPatterns.get(index).put(count, positivePrefix);
negativePrefixPatterns.get(index).put(count, negativePrefix);
positiveSuffixPatterns.get(index).put(count, positiveSuffix);
@@ -1625,10 +1632,25 @@
position += matchedNegPrefix.length();
cnfMultiplier = matchedNegIndex != -1
? divisors.get(matchedNegIndex) : 1L;
}
+ // If the divisor is negative, no number or suffix exists.
+ // Return the absolute divisor value as the parse result.
+ if (cnfMultiplier instanceof BigInteger) {
+ BigInteger biMultiplier = (BigInteger)cnfMultiplier;
+ if (biMultiplier.signum() == -1) {
+ pos.index = position;
+ return biMultiplier.negate();
+ }
+ } else {
+ if (cnfMultiplier.longValue() < 0) {
+ pos.index = position;
+ return Math.abs(cnfMultiplier.longValue());
+ }
+ }
+
digitList.setRoundingMode(getRoundingMode());
boolean[] status = new boolean[STATUS_LENGTH];
// Call DecimalFormat.subparseNumber() method to parse the
// number part of the input text
@@ -1706,18 +1728,18 @@
}
return cnfResult;
}
}
+ private static final Pattern DIGITS = Pattern.compile("\\p{Nd}+");
/**
* Parse the number part in the input text into a number
*
* @param text input text to be parsed
* @param position starting position
* @return the number
*/
- private static Pattern DIGITS = Pattern.compile("\\p{Nd}+");
private double parseNumberPart(String text, int position) {
if (text.startsWith(symbols.getInfinity(), position)) {
return Double.POSITIVE_INFINITY;
} else if (!text.startsWith(symbols.getNaN(), position)) {
Matcher m = DIGITS.matcher(text);
@@ -1819,13 +1841,11 @@
// Check with the compact affixes which are non empty and
// do not match with default affix
if (!affix.isEmpty() && !affix.equals(defaultAffix)) {
// Look ahead only for the longer match than the previous match
if (matchedAffix.length() < affix.length()) {
- if (text.regionMatches(position, affix, 0, affix.length())) {
- return true;
- }
+ return text.regionMatches(position, affix, 0, affix.length());
}
}
return false;
}
@@ -2358,11 +2378,11 @@
/**
* Abstraction of affix patterns for each "count" tag.
*/
private final class Patterns {
- private Map<String, String> patternsMap = new HashMap<>();
+ private final Map<String, String> patternsMap = new HashMap<>();
void put(String count, String pattern) {
patternsMap.put(count, pattern);
}
@@ -2371,17 +2391,16 @@
patternsMap.getOrDefault("other", ""));
}
Patterns expandAffix() {
Patterns ret = new Patterns();
- patternsMap.entrySet().stream()
- .forEach(e -> ret.put(e.getKey(), CompactNumberFormat.this.expandAffix(e.getValue())));
+ patternsMap.forEach((key, value) -> ret.put(key, CompactNumberFormat.this.expandAffix(value)));
return ret;
}
}
- private final int getIntegerPart(double number, double divisor) {
+ private int getIntegerPart(double number, double divisor) {
return BigDecimal.valueOf(number)
.divide(BigDecimal.valueOf(divisor), roundingMode).intValue();
}
/**
@@ -2392,29 +2411,27 @@
*/
private String getPluralCategory(double input) {
if (rulesMap != null) {
return rulesMap.entrySet().stream()
.filter(e -> matchPluralRule(e.getValue(), input))
- .map(e -> e.getKey())
+ .map(Map.Entry::getKey)
.findFirst()
.orElse("other");
}
// defaults to "other"
return "other";
}
private static boolean matchPluralRule(String condition, double input) {
return Arrays.stream(condition.split("or"))
- .anyMatch(and_condition -> {
- return Arrays.stream(and_condition.split("and"))
- .allMatch(r -> relationCheck(r, input));
- });
+ .anyMatch(and_condition -> Arrays.stream(and_condition.split("and"))
+ .allMatch(r -> relationCheck(r, input)));
}
- private final static String NAMED_EXPR = "(?<op>[niftvw]{1})\\s*((?<div>[/\\%])\\s*(?<val>\\d+))*";
- private final static String NAMED_RELATION = "(?<rel>!{0,1}=)";
+ private final static String NAMED_EXPR = "(?<op>[niftvw])\\s*((?<div>[/%])\\s*(?<val>\\d+))*";
+ private final static String NAMED_RELATION = "(?<rel>!?=)";
private final static String NAMED_VALUE_RANGE = "(?<start>\\d+)\\.\\.(?<end>\\d+)|(?<value>\\d+)";
private final static Pattern EXPR_PATTERN = Pattern.compile(NAMED_EXPR);
private final static Pattern RELATION_PATTERN = Pattern.compile(NAMED_RELATION);
private final static Pattern VALUE_RANGE_PATTERN = Pattern.compile(NAMED_VALUE_RANGE);
@@ -2460,11 +2477,11 @@
if (rel.find(expr.end())) {
var conditions =
Arrays.stream(relation.substring(rel.end()).split(","));
- if (rel.group("rel").equals("!=")) {
+ if (Objects.equals(rel.group("rel"), "!=")) {
return conditions.noneMatch(c -> valOrRangeMatches(c, lop));
} else {
return conditions.anyMatch(c -> valOrRangeMatches(c, lop));
}
}
@@ -2485,24 +2502,20 @@
if (input == Double.POSITIVE_INFINITY) {
ret =input;
} else {
String op = expr.group("op");
- if (op.equals("n") || op.equals("i")) {
+ if (Objects.equals(op, "n") || Objects.equals(op, "i")) {
ret = input;
}
String divop = expr.group("div");
if (divop != null) {
String divisor = expr.group("val");
switch (divop) {
- case "%":
- ret %= Double.parseDouble(divisor);
- break;
- case "/":
- ret /= Double.parseDouble(divisor);
- break;
+ case "%" -> ret %= Double.parseDouble(divisor);
+ case "/" -> ret /= Double.parseDouble(divisor);
}
}
}
return ret;
< prev index next >