Make DecimalType, QuantityType, PercentType accept lowercased exponent notation (#3834)

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
pull/3815/head^2
jimtng 2023-10-09 18:59:25 +10:00 committed by GitHub
parent 09b3160a55
commit 304453ec58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 37 additions and 8 deletions

View File

@ -82,7 +82,7 @@ public class DecimalType extends Number implements PrimitiveType, State, Command
DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(locale);
df.setParseBigDecimal(true);
ParsePosition position = new ParsePosition(0);
BigDecimal parsedValue = (BigDecimal) df.parseObject(value, position);
BigDecimal parsedValue = (BigDecimal) df.parseObject(value.toUpperCase(locale), position);
if (parsedValue == null || position.getErrorIndex() != -1 || position.getIndex() < value.length()) {
throw new NumberFormatException("Invalid BigDecimal value: " + value);
}

View File

@ -70,11 +70,11 @@ public class QuantityType<T extends Quantity<T>> extends Number
public static final QuantityType<Dimensionless> ZERO = new QuantityType<>(0, AbstractUnit.ONE);
public static final QuantityType<Dimensionless> ONE = new QuantityType<>(1, AbstractUnit.ONE);
// Regular expression to split unit from value
// split on any blank character, even none (\\s*) which occurs after a digit (?<=\\d) and before
// a "unit" character ?=[a-zA-Z°µ%'] which itself must not be preceded by plus/minus digit (?![\\+\\-]?\\d).
// The later would be an exponent from the scalar value.
private static final String UNIT_PATTERN = "(?<=\\d)\\s*(?=[a-zA-Z°µ%'](?![\\+\\-]?\\d))";
// Regular expression to split unit from value. Split on any blank character, even none (\\s*)
// which occurs after a digit (?<=\\d) and before a "unit" character ?=[a-zA-Z°µ\u03BC%']
// which itself must not be preceded by plus/minus digit (?![\\+\\-]?\\d).
// The latter would be an exponent from the scalar value.
private static final String UNIT_PATTERN = "(?<=\\d)\\s*(?=[a-zA-Z°µ\u03BC%'](?![\\+\\-]?\\d))";
static {
UnitInitializer.init();
@ -119,13 +119,16 @@ public class QuantityType<T extends Quantity<T>> extends Number
public QuantityType(String value, Locale locale) {
String[] constituents = value.split(UNIT_PATTERN);
if (constituents.length > 0) {
constituents[0] = constituents[0].toUpperCase(locale);
}
// getQuantity needs a space between numeric value and unit
String formatted = String.join(" ", constituents);
if (!formatted.contains(" ")) {
DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(locale);
df.setParseBigDecimal(true);
ParsePosition position = new ParsePosition(0);
BigDecimal parsedValue = (BigDecimal) df.parseObject(value, position);
BigDecimal parsedValue = (BigDecimal) df.parseObject(formatted, position);
if (parsedValue == null || position.getErrorIndex() != -1 || position.getIndex() < value.length()) {
throw new NumberFormatException("Invalid BigDecimal value: " + value);
}
@ -294,7 +297,7 @@ public class QuantityType<T extends Quantity<T>> extends Number
* change the dimension.
*
* @param targetUnit the unit to which this {@link QuantityType} will be converted to.
* @return the new {@link QuantityType} in the given {@link Unit} or {@code null} in case of an erro.
* @return the new {@link QuantityType} in the given {@link Unit} or {@code null} in case of an error.
*/
public @Nullable QuantityType<?> toInvertibleUnit(Unit<?> targetUnit) {
// only invert if unit is not equal and inverse is compatible and targetUnit is not ONE

View File

@ -90,6 +90,12 @@ public class DecimalTypeTest {
DecimalType.valueOf(value);
}
@Test
public void testLowerCaseExponents() {
assertEquals(DecimalType.valueOf("1e3"), DecimalType.valueOf("1E3"));
assertEquals(DecimalType.valueOf("2.5e-3"), DecimalType.valueOf("2.5E-3"));
}
@ParameterizedTest
@MethodSource("locales")
public void testLocalizedStringConstruction(Locale defaultLocale) {

View File

@ -77,6 +77,12 @@ public class PercentTypeTest {
PercentType.valueOf(value);
}
@Test
public void testLowerCaseExponents() {
assertEquals(PercentType.valueOf("1e2"), PercentType.valueOf("1E2"));
assertEquals(PercentType.valueOf("1.1e1"), PercentType.valueOf("1.1E1"));
}
@ParameterizedTest
@MethodSource("locales")
public void testLocalizedStringConstruction(Locale defaultLocale) {

View File

@ -146,6 +146,20 @@ public class QuantityTypeTest {
QuantityType.valueOf("2m");
}
@Test
public void testLowerCaseExponents() {
assertEquals(QuantityType.valueOf("10e3"), QuantityType.valueOf("10E3"));
assertEquals(QuantityType.valueOf("1.1e3 W"), QuantityType.valueOf("1.1E3 W"));
assertEquals(QuantityType.valueOf("1.1e3 m"), QuantityType.valueOf("1.1E3 m"));
assertEquals(QuantityType.valueOf("1.1e3m"), QuantityType.valueOf("1.1E3 m"));
assertEquals(QuantityType.valueOf("1.1e3m³"), QuantityType.valueOf("1.1E3 m³"));
assertEquals(QuantityType.valueOf("1.1e3m·cm"), QuantityType.valueOf("1.1E3 m·cm"));
assertEquals(QuantityType.valueOf("1.1e3 \u03BCm"), QuantityType.valueOf("1.1E3 µm"));
assertEquals(QuantityType.valueOf("1.1e3\u03BCm"), QuantityType.valueOf("1.1E3 µm"));
assertEquals(QuantityType.valueOf("1.1e3 \u00B5m"), QuantityType.valueOf("1.1E3 µm"));
assertEquals(QuantityType.valueOf("1.1e3\u00B5m"), QuantityType.valueOf("1.1E3 µm"));
}
@ParameterizedTest
@MethodSource("locales")
public void testLocalizedStringConstruction(Locale defaultLocale) {