From 304453ec58abe4a72e8b3a898acc74adc59c4f01 Mon Sep 17 00:00:00 2001 From: jimtng <2554958+jimtng@users.noreply.github.com> Date: Mon, 9 Oct 2023 18:59:25 +1000 Subject: [PATCH] Make DecimalType, QuantityType, PercentType accept lowercased exponent notation (#3834) Signed-off-by: Jimmy Tanagra --- .../openhab/core/library/types/DecimalType.java | 2 +- .../core/library/types/QuantityType.java | 17 ++++++++++------- .../core/library/types/DecimalTypeTest.java | 6 ++++++ .../core/library/types/PercentTypeTest.java | 6 ++++++ .../core/library/types/QuantityTypeTest.java | 14 ++++++++++++++ 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/bundles/org.openhab.core/src/main/java/org/openhab/core/library/types/DecimalType.java b/bundles/org.openhab.core/src/main/java/org/openhab/core/library/types/DecimalType.java index 137a0f1500..ea70428121 100644 --- a/bundles/org.openhab.core/src/main/java/org/openhab/core/library/types/DecimalType.java +++ b/bundles/org.openhab.core/src/main/java/org/openhab/core/library/types/DecimalType.java @@ -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); } diff --git a/bundles/org.openhab.core/src/main/java/org/openhab/core/library/types/QuantityType.java b/bundles/org.openhab.core/src/main/java/org/openhab/core/library/types/QuantityType.java index 779bdfcd67..d7059de031 100644 --- a/bundles/org.openhab.core/src/main/java/org/openhab/core/library/types/QuantityType.java +++ b/bundles/org.openhab.core/src/main/java/org/openhab/core/library/types/QuantityType.java @@ -70,11 +70,11 @@ public class QuantityType> extends Number public static final QuantityType ZERO = new QuantityType<>(0, AbstractUnit.ONE); public static final QuantityType 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> 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> 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 diff --git a/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/DecimalTypeTest.java b/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/DecimalTypeTest.java index 3114464945..1a591ae21c 100644 --- a/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/DecimalTypeTest.java +++ b/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/DecimalTypeTest.java @@ -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) { diff --git a/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/PercentTypeTest.java b/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/PercentTypeTest.java index e9871ac623..e29066c087 100644 --- a/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/PercentTypeTest.java +++ b/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/PercentTypeTest.java @@ -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) { diff --git a/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/QuantityTypeTest.java b/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/QuantityTypeTest.java index 248a090dec..e521be9e8c 100644 --- a/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/QuantityTypeTest.java +++ b/bundles/org.openhab.core/src/test/java/org/openhab/core/library/types/QuantityTypeTest.java @@ -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) {