mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8333755: NumberFormat integer only parsing breaks when format has suffix
Reviewed-by: naoto
This commit is contained in:
parent
b5d589623c
commit
bffc8484c3
5 changed files with 169 additions and 101 deletions
|
@ -2150,10 +2150,7 @@ public class DecimalFormat extends NumberFormat {
|
|||
* #getGroupingSize()} is not adhered to
|
||||
* <li> {@link #isGroupingUsed()} returns {@code false}, and the grouping
|
||||
* symbol is found
|
||||
* <li> {@link #isParseIntegerOnly()} returns {@code true}, and the decimal
|
||||
* separator is found
|
||||
* <li> {@link #isGroupingUsed()} returns {@code true} and {@link
|
||||
* #isParseIntegerOnly()} returns {@code false}, and the grouping
|
||||
* <li> {@link #isGroupingUsed()} returns {@code true} and the grouping
|
||||
* symbol occurs after the decimal separator
|
||||
* <li> Any other characters are found, that are not the expected symbols,
|
||||
* and are not digits that occur within the numerical portion
|
||||
|
@ -2379,7 +2376,8 @@ public class DecimalFormat extends NumberFormat {
|
|||
|
||||
// position will serve as new index when success, otherwise it will
|
||||
// serve as errorIndex when failure
|
||||
position = subparseNumber(text, position, digits, true, isExponent, status);
|
||||
NumericPosition pos = subparseNumber(text, position, digits, true, isExponent, status);
|
||||
position = pos.fullPos;
|
||||
|
||||
// First character after the prefix was un-parseable, should
|
||||
// fail regardless if lenient or strict.
|
||||
|
@ -2422,9 +2420,15 @@ public class DecimalFormat extends NumberFormat {
|
|||
return false;
|
||||
}
|
||||
|
||||
// No failures, thus increment the index by the suffix
|
||||
parsePosition.index = position +
|
||||
(gotPositive ? positiveSuffix.length() : negativeSuffix.length());
|
||||
// When parsing integer only, index should be int pos
|
||||
// If intPos is 0, the entire value was integer
|
||||
if (isParseIntegerOnly() && pos.intPos > 0) {
|
||||
parsePosition.index = pos.intPos;
|
||||
} else {
|
||||
// increment the index by the suffix
|
||||
parsePosition.index = position +
|
||||
(gotPositive ? positiveSuffix.length() : negativeSuffix.length());
|
||||
}
|
||||
} else {
|
||||
parsePosition.index = position;
|
||||
}
|
||||
|
@ -2437,6 +2441,19 @@ public class DecimalFormat extends NumberFormat {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* NumericPosition is a helper record class that stores two indices of interest.
|
||||
* {@code fullPos} is either the first unparseable character or -1 in case
|
||||
* of no valid number parsed. {@code intPos} reflects the position of
|
||||
* a parsed decimal symbol, if one exists. When parsing with {@code isParseIntegerOnly()},
|
||||
* {@code fullPos} is used to match the suffix, and reset the {@code ParsePosition}
|
||||
* index to {@code intPos}.
|
||||
*
|
||||
* @param fullPos an index that reflects the full traversal of the numerical String
|
||||
* @param intPos an index that reflects the position of a parsed decimal symbol.
|
||||
*/
|
||||
record NumericPosition(int fullPos, int intPos) {}
|
||||
|
||||
/**
|
||||
* Parses a number from the given {@code text}. The text is parsed
|
||||
* beginning at {@code position}, until an unparseable character is seen.
|
||||
|
@ -2449,14 +2466,15 @@ public class DecimalFormat extends NumberFormat {
|
|||
* @param status upon return contains boolean status flags indicating
|
||||
* whether the value is infinite and whether it is
|
||||
* positive
|
||||
* @return returns the position of the first unparseable character or
|
||||
* -1 in case of no valid number parsed
|
||||
* @return returns a {@code NumericPosition} that stores both a full
|
||||
* traversal index, and an int only index.
|
||||
*/
|
||||
int subparseNumber(String text, int position,
|
||||
DigitList digits, boolean checkExponent,
|
||||
boolean isExponent, boolean[] status) {
|
||||
NumericPosition subparseNumber(String text, int position,
|
||||
DigitList digits, boolean checkExponent,
|
||||
boolean isExponent, boolean[] status) {
|
||||
// process digits or Inf, find decimal position
|
||||
status[STATUS_INFINITE] = false;
|
||||
int intIndex = 0;
|
||||
if (!isExponent && text.regionMatches(position, symbols.getInfinity(), 0,
|
||||
symbols.getInfinity().length())) {
|
||||
position += symbols.getInfinity().length();
|
||||
|
@ -2516,7 +2534,7 @@ public class DecimalFormat extends NumberFormat {
|
|||
if (parseStrict && isGroupingUsed() && position == startPos + groupingSize
|
||||
&& prevSeparatorIndex == -groupingSize && !sawDecimal
|
||||
&& digit >= 0 && digit <= 9) {
|
||||
return position;
|
||||
return new NumericPosition(position, intIndex);
|
||||
}
|
||||
|
||||
if (digit == 0) {
|
||||
|
@ -2538,37 +2556,44 @@ public class DecimalFormat extends NumberFormat {
|
|||
--digits.decimalAt;
|
||||
} else {
|
||||
++digitCount;
|
||||
digits.append((char)(digit + '0'));
|
||||
if (!sawDecimal || !isParseIntegerOnly()) {
|
||||
digits.append((char)(digit + '0'));
|
||||
}
|
||||
}
|
||||
} else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above
|
||||
sawDigit = true;
|
||||
++digitCount;
|
||||
digits.append((char)(digit + '0'));
|
||||
if (!sawDecimal || !isParseIntegerOnly()) {
|
||||
digits.append((char) (digit + '0'));
|
||||
}
|
||||
|
||||
// Cancel out backup setting (see grouping handler below)
|
||||
backup = -1;
|
||||
} else if (!isExponent && ch == decimal) {
|
||||
// Check grouping size on decimal separator
|
||||
if (parseStrict && isGroupingViolation(position, prevSeparatorIndex)) {
|
||||
return groupingViolationIndex(position, prevSeparatorIndex);
|
||||
return new NumericPosition(
|
||||
groupingViolationIndex(position, prevSeparatorIndex), intIndex);
|
||||
}
|
||||
// If we're only parsing integers, or if we ALREADY saw the
|
||||
// decimal, then don't parse this one.
|
||||
if (isParseIntegerOnly() || sawDecimal) {
|
||||
if (sawDecimal) {
|
||||
break;
|
||||
}
|
||||
intIndex = position;
|
||||
digits.decimalAt = digitCount; // Not digits.count!
|
||||
sawDecimal = true;
|
||||
} else if (!isExponent && ch == grouping && isGroupingUsed()) {
|
||||
if (parseStrict) {
|
||||
// text should not start with grouping when strict
|
||||
if (position == startPos) {
|
||||
return startPos;
|
||||
return new NumericPosition(startPos, intIndex);
|
||||
}
|
||||
// when strict, fail if grouping occurs after decimal OR
|
||||
// current group violates grouping size
|
||||
if (sawDecimal || (isGroupingViolation(position, prevSeparatorIndex))) {
|
||||
return groupingViolationIndex(position, prevSeparatorIndex);
|
||||
return new NumericPosition(
|
||||
groupingViolationIndex(position, prevSeparatorIndex), intIndex);
|
||||
}
|
||||
prevSeparatorIndex = position; // track previous
|
||||
} else {
|
||||
|
@ -2621,7 +2646,8 @@ public class DecimalFormat extends NumberFormat {
|
|||
// "1,234%" and "1,234" both end with pos = 5, since '%' breaks
|
||||
// the loop before incrementing position. In both cases, check
|
||||
// should be done at pos = 4
|
||||
return groupingViolationIndex(position - 1, prevSeparatorIndex);
|
||||
return new NumericPosition(
|
||||
groupingViolationIndex(position - 1, prevSeparatorIndex), intIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2636,8 +2662,9 @@ public class DecimalFormat extends NumberFormat {
|
|||
digits.decimalAt = digitCount; // Not digits.count!
|
||||
}
|
||||
|
||||
// Adjust for exponent, if any
|
||||
if (exponent != 0) {
|
||||
// If parsing integer only, adjust exponent if it occurs
|
||||
// in integer portion, otherwise ignore it
|
||||
if (!sawDecimal || !isParseIntegerOnly()) {
|
||||
digits.decimalAt = shiftDecimalAt(digits.decimalAt, exponent);
|
||||
}
|
||||
|
||||
|
@ -2646,10 +2673,10 @@ public class DecimalFormat extends NumberFormat {
|
|||
// parse "$" with pattern "$#0.00". (return index 0 and error
|
||||
// index 1).
|
||||
if (!sawDigit && digitCount == 0) {
|
||||
return -1;
|
||||
return new NumericPosition(-1, intIndex);
|
||||
}
|
||||
}
|
||||
return position;
|
||||
return new NumericPosition(position, intIndex);
|
||||
}
|
||||
|
||||
// Calculate the final decimal position based off the exponent value
|
||||
|
@ -2917,7 +2944,8 @@ public class DecimalFormat extends NumberFormat {
|
|||
* have '{@code U+2030}'.
|
||||
*
|
||||
* <P>Example: with multiplier 100, 1.23 is formatted as "123", and
|
||||
* "123" is parsed into 1.23.
|
||||
* "123" is parsed into 1.23. If {@code isParseIntegerOnly()} returns {@code true},
|
||||
* "123" is parsed into 1.
|
||||
*
|
||||
* @param newValue the new multiplier
|
||||
* @see #getMultiplier
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue