diff options
author | Adrien Hopkins <ahopk127@my.yorku.ca> | 2021-12-02 16:55:05 -0500 |
---|---|---|
committer | Adrien Hopkins <ahopk127@my.yorku.ca> | 2021-12-02 16:55:05 -0500 |
commit | cc79db65bc347c50267d0a719278ef1d90cf6b1a (patch) | |
tree | 65717e8d7e75247ced380a72842c50b94fc61a0e /src/main/java/sevenUnits | |
parent | c4ae6887c32ee8d2e9e8853ffd12721d4db2fd3b (diff) | |
parent | 9c30c3ad4d4658964e2bb2bb5be6c2eebbfbe8af (diff) |
Merge branch 'release-0.3.2'
Diffstat (limited to 'src/main/java/sevenUnits')
-rw-r--r-- | src/main/java/sevenUnits/ProgramInfo.java | 2 | ||||
-rw-r--r-- | src/main/java/sevenUnits/unit/BritishImperial.java | 39 | ||||
-rw-r--r-- | src/main/java/sevenUnits/unit/LinearUnitValue.java | 17 | ||||
-rw-r--r-- | src/main/java/sevenUnits/unit/UnitDatabase.java | 55 | ||||
-rw-r--r-- | src/main/java/sevenUnits/unit/UnitValue.java | 3 | ||||
-rw-r--r-- | src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java | 2 | ||||
-rw-r--r-- | src/main/java/sevenUnits/utils/ExpressionParser.java | 12 | ||||
-rw-r--r-- | src/main/java/sevenUnits/utils/ObjectProduct.java | 135 | ||||
-rw-r--r-- | src/main/java/sevenUnits/utils/UncertainDouble.java | 15 |
9 files changed, 159 insertions, 121 deletions
diff --git a/src/main/java/sevenUnits/ProgramInfo.java b/src/main/java/sevenUnits/ProgramInfo.java index 2a0edde..31e43c7 100644 --- a/src/main/java/sevenUnits/ProgramInfo.java +++ b/src/main/java/sevenUnits/ProgramInfo.java @@ -24,7 +24,7 @@ package sevenUnits; */ public final class ProgramInfo { - public static final String VERSION = "0.3.1"; + public static final String VERSION = "0.3.2"; private ProgramInfo() {} diff --git a/src/main/java/sevenUnits/unit/BritishImperial.java b/src/main/java/sevenUnits/unit/BritishImperial.java index 81a3f2a..743beeb 100644 --- a/src/main/java/sevenUnits/unit/BritishImperial.java +++ b/src/main/java/sevenUnits/unit/BritishImperial.java @@ -37,7 +37,7 @@ public final class BritishImperial { public static final LinearUnit ROOD = Length.ROD.times(Length.FURLONG); public static final LinearUnit ACRE = Length.FURLONG.times(Length.CHAIN); } - + /** * Imperial units that measure length * @@ -46,7 +46,8 @@ public final class BritishImperial { */ public static final class Length { /** - * According to the International Yard and Pound of 1959, a yard is defined as exactly 0.9144 metres. + * According to the International Yard and Pound of 1959, a yard is + * defined as exactly 0.9144 metres. */ public static final LinearUnit YARD = Metric.METRE.times(0.9144); public static final LinearUnit FOOT = YARD.dividedBy(3); @@ -56,15 +57,15 @@ public final class BritishImperial { public static final LinearUnit FURLONG = CHAIN.times(10); public static final LinearUnit MILE = FURLONG.times(8); public static final LinearUnit LEAGUE = MILE.times(3); - + public static final LinearUnit NAUTICAL_MILE = Metric.METRE.times(1852); public static final LinearUnit CABLE = NAUTICAL_MILE.dividedBy(10); public static final LinearUnit FATHOM = CABLE.dividedBy(100); - + public static final LinearUnit ROD = YARD.times(5.5); public static final LinearUnit LINK = ROD.dividedBy(25); } - + /** * British Imperial units that measure mass. * @@ -82,7 +83,7 @@ public final class BritishImperial { public static final LinearUnit LONG_TON = HUNDREDWEIGHT.times(20); public static final LinearUnit SLUG = Metric.KILOGRAM.times(14.59390294); } - + /** * British Imperial units that measure volume * @@ -90,27 +91,33 @@ public final class BritishImperial { * @since 2019-11-08 */ public static final class Volume { - public static final LinearUnit FLUID_OUNCE = Metric.LITRE.withPrefix(Metric.MILLI).times(28.4130625); + public static final LinearUnit FLUID_OUNCE = Metric.LITRE + .withPrefix(Metric.MILLI).times(28.4130625); public static final LinearUnit GILL = FLUID_OUNCE.times(5); public static final LinearUnit PINT = FLUID_OUNCE.times(20); public static final LinearUnit QUART = PINT.times(2); public static final LinearUnit GALLON = QUART.times(4); public static final LinearUnit PECK = GALLON.times(2); public static final LinearUnit BUSHEL = PECK.times(4); - + public static final LinearUnit CUBIC_INCH = Length.INCH.toExponent(3); public static final LinearUnit CUBIC_FOOT = Length.FOOT.toExponent(3); public static final LinearUnit CUBIC_YARD = Length.YARD.toExponent(3); public static final LinearUnit ACRE_FOOT = Area.ACRE.times(Length.FOOT); } - - public static final LinearUnit OUNCE_FORCE = Mass.OUNCE.times(Metric.Constants.EARTH_GRAVITY); - public static final LinearUnit POUND_FORCE = Mass.POUND.times(Metric.Constants.EARTH_GRAVITY); - - public static final LinearUnit BRITISH_THERMAL_UNIT = Metric.JOULE.times(1055.06); + + public static final LinearUnit OUNCE_FORCE = Mass.OUNCE + .times(Metric.Constants.EARTH_GRAVITY); + public static final LinearUnit POUND_FORCE = Mass.POUND + .times(Metric.Constants.EARTH_GRAVITY); + + public static final LinearUnit BRITISH_THERMAL_UNIT = Metric.JOULE + .times(1055.06); public static final LinearUnit CALORIE = Metric.JOULE.times(4.184); public static final LinearUnit KILOCALORIE = Metric.JOULE.times(4184); - - public static final Unit FAHRENHEIT = Unit.fromConversionFunctions(Metric.KELVIN.getBase(), - tempK -> tempK * 1.8 - 459.67, tempF -> (tempF + 459.67) / 1.8); + + public static final Unit FAHRENHEIT = Unit + .fromConversionFunctions(Metric.KELVIN.getBase(), + tempK -> tempK * 1.8 - 459.67, tempF -> (tempF + 459.67) / 1.8) + .withName(NameSymbol.of("degrees Fahrenheit", "\u00B0F")); } diff --git a/src/main/java/sevenUnits/unit/LinearUnitValue.java b/src/main/java/sevenUnits/unit/LinearUnitValue.java index a36d568..a50e1f5 100644 --- a/src/main/java/sevenUnits/unit/LinearUnitValue.java +++ b/src/main/java/sevenUnits/unit/LinearUnitValue.java @@ -324,17 +324,18 @@ public final class LinearUnitValue { // get rounded strings // if showUncertainty is true, add brackets around the string - final String valueString = showUncertainty ? "(" - : "" + this.value.toString(showUncertainty) - + (showUncertainty ? ")" : ""); - final String baseValueString = showUncertainty ? "(" - : "" + baseValue.toString(showUncertainty) - + (showUncertainty ? ")" : ""); + final String valueString = (showUncertainty ? "(" : "") + + this.value.toString(showUncertainty) + + (showUncertainty ? ")" : ""); + final String baseValueString = (showUncertainty ? "(" : "") + + baseValue.toString(showUncertainty) + + (showUncertainty ? ")" : ""); // create string - if (primaryName.isEmpty() && symbol.isEmpty()) + if (chosenName == null) return String.format("%s unnamed unit (= %s %s)", valueString, - baseValueString, this.unit.getBase()); + baseValueString, this.unit.getBase() + .toString(unit -> unit.getSymbol().orElseThrow())); else return String.format("%s %s", valueString, chosenName); } diff --git a/src/main/java/sevenUnits/unit/UnitDatabase.java b/src/main/java/sevenUnits/unit/UnitDatabase.java index b45d9cf..18ac619 100644 --- a/src/main/java/sevenUnits/unit/UnitDatabase.java +++ b/src/main/java/sevenUnits/unit/UnitDatabase.java @@ -243,7 +243,8 @@ public final class UnitDatabase { return false; else { if (this.prefixNames.isEmpty()) - return this.unitNamePosition >= this.unitNames.size() - 1; + return this.prefixCoordinates.isEmpty() + && this.unitNamePosition < this.unitNames.size(); else return true; } @@ -557,7 +558,8 @@ public final class UnitDatabase { return false; else { if (this.prefixNames.isEmpty()) - return this.unitNamePosition >= this.unitNames.size() - 1; + return this.prefixCoordinates.isEmpty() + && this.unitNamePosition < this.unitNames.size(); else return true; } @@ -1038,7 +1040,7 @@ public final class UnitDatabase { @Override public String toString() { if (this.units.isEmpty() || this.prefixes.isEmpty()) - return super.toString(); + return new HashMap<>(this).toString(); else return String.format( "Infinite map of name-unit entries created from units %s and prefixes %s", @@ -1161,7 +1163,7 @@ public final class UnitDatabase { * @return true if entry represents a removable duplicate entry of unitMap. * @since 2021-05-22 */ - private static boolean isRemovableDuplicate(Map<String, Unit> unitMap, + static boolean isRemovableDuplicate(Map<String, Unit> unitMap, Entry<String, Unit> entry) { for (final Entry<String, Unit> e : unitMap.entrySet()) { final String name = e.getKey(); @@ -1344,10 +1346,10 @@ public final class UnitDatabase { final String name = lineMatcher.group(1); final String expression = lineMatcher.group(2); - if (name.endsWith(" ")) { - System.err.printf("Warning - line %d's dimension name ends in a space", - lineCounter); - } + // if (name.endsWith(" ")) { + // System.err.printf("Warning - line %d's dimension name ends in a space", + // lineCounter); + // } // if expression is "!", search for an existing dimension // if no unit found, throw an error @@ -1360,7 +1362,7 @@ public final class UnitDatabase { final ObjectProduct<BaseDimension> dimension; try { dimension = this.getDimensionFromExpression(expression); - } catch (final IllegalArgumentException e) { + } catch (final IllegalArgumentException | NoSuchElementException e) { System.err.printf("Parsing error on line %d:%n", lineCounter); throw e; } @@ -1427,10 +1429,11 @@ public final class UnitDatabase { final String expression = lineMatcher.group(2); - if (name.endsWith(" ")) { - System.err.printf("Warning - line %d's unit name ends in a space", - lineCounter); - } + // this code should never occur + // if (name.endsWith(" ")) { + // System.err.printf("Warning - line %d's unit name ends in a space", + // lineCounter); + // } // if expression is "!", search for an existing unit // if no unit found, throw an error @@ -1443,7 +1446,8 @@ public final class UnitDatabase { final UnitPrefix prefix; try { prefix = this.getPrefixFromExpression(expression); - } catch (final IllegalArgumentException e) { + } catch (final IllegalArgumentException + | NoSuchElementException e) { System.err.printf("Parsing error on line %d:%n", lineCounter); throw e; } @@ -1453,7 +1457,8 @@ public final class UnitDatabase { final Unit unit; try { unit = this.getUnitFromExpression(expression); - } catch (final IllegalArgumentException e) { + } catch (final IllegalArgumentException + | NoSuchElementException e) { System.err.printf("Parsing error on line %d:%n", lineCounter); throw e; } @@ -1581,8 +1586,15 @@ public final class UnitDatabase { } return base.toExponent(exponent); + } else { + final ObjectProduct<BaseDimension> dimension = this.dimensions + .get(name); + if (dimension == null) + throw new NoSuchElementException( + "No dimension with name \"" + name + "\"."); + else + return dimension; } - return this.dimensions.get(name); } /** @@ -1635,7 +1647,7 @@ public final class UnitDatabase { * @since 2019-03-22 * @since v0.2.0 */ - private LinearUnit getLinearUnit(final String name) { + LinearUnit getLinearUnit(final String name) { // see if I am using a function-unit like tempC(100) Objects.requireNonNull(name, "name may not be null"); if (name.contains("(") && name.contains(")")) { @@ -1670,7 +1682,7 @@ public final class UnitDatabase { * @return {@code LinearUnitValue} instance * @since 2020-08-04 */ - private LinearUnitValue getLinearUnitValue(final String name) { + LinearUnitValue getLinearUnitValue(final String name) { try { // try to parse it as a number - otherwise it is not a number! final BigDecimal number = new BigDecimal(name); @@ -1695,7 +1707,12 @@ public final class UnitDatabase { try { return UnitPrefix.valueOf(Double.parseDouble(name)); } catch (final NumberFormatException e) { - return this.prefixes.get(name); + final UnitPrefix prefix = this.prefixes.get(name); + if (prefix == null) + throw new NoSuchElementException( + "No prefix with name \"" + name + "\"."); + else + return prefix; } } diff --git a/src/main/java/sevenUnits/unit/UnitValue.java b/src/main/java/sevenUnits/unit/UnitValue.java index 2fedd81..f6d18f8 100644 --- a/src/main/java/sevenUnits/unit/UnitValue.java +++ b/src/main/java/sevenUnits/unit/UnitValue.java @@ -163,7 +163,8 @@ public final class UnitValue { if (primaryName.isEmpty() && symbol.isEmpty()) { final double baseValue = this.getUnit().convertToBase(this.getValue()); return String.format("%s unnamed unit (= %s %s)", this.getValue(), - baseValue, this.getUnit().getBase()); + baseValue, this.getUnit().getBase() + .toString(unit -> unit.getSymbol().orElseThrow())); } else { final String unitName = symbol.orElse(primaryName.get()); return this.getValue() + " " + unitName; diff --git a/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java b/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java index 2adb579..bee4dd1 100644 --- a/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java +++ b/src/main/java/sevenUnits/utils/ConditionalExistenceCollections.java @@ -283,7 +283,7 @@ public final class ConditionalExistenceCollections { @Override public Set<K> keySet() { - return conditionalExistenceSet(super.keySet(), + return conditionalExistenceSet(this.map.keySet(), k -> this.entryExistenceCondition.test(this.getEntry(k))); } diff --git a/src/main/java/sevenUnits/utils/ExpressionParser.java b/src/main/java/sevenUnits/utils/ExpressionParser.java index 1d3d44d..941c2a4 100644 --- a/src/main/java/sevenUnits/utils/ExpressionParser.java +++ b/src/main/java/sevenUnits/utils/ExpressionParser.java @@ -461,10 +461,12 @@ public final class ExpressionParser<T> { * * @param expression expression * @return expression in RPN + * @throws IllegalArgumentException if expression is invalid (e.g. + * "{@code 3 *}") * @since 2019-03-17 * @since v0.2.0 */ - private String convertExpressionToReversePolish(final String expression) { + String convertExpressionToReversePolish(final String expression) { Objects.requireNonNull(expression, "expression must not be null."); final List<String> components = new ArrayList<>(); @@ -541,6 +543,9 @@ public final class ExpressionParser<T> { switch (this .getTokenType(components.get(highestPriorityOperatorPosition))) { case UNARY_OPERATOR: + if (components.size() < 2) + throw new IllegalArgumentException( + "Invalid expression \"" + expression + "\""); final String unaryOperator = components .remove(highestPriorityOperatorPosition); final String operand = components @@ -549,6 +554,9 @@ public final class ExpressionParser<T> { operand + " " + unaryOperator); break; case BINARY_OPERATOR: + if (components.size() < 3) + throw new IllegalArgumentException( + "Invalid expression \"" + expression + "\""); final String binaryOperator = components .remove(highestPriorityOperatorPosition); final String operand1 = components @@ -672,7 +680,7 @@ public final class ExpressionParser<T> { * @since 2019-03-14 * @since v0.2.0 */ - private T parseReversePolishExpression(final String expression) { + T parseReversePolishExpression(final String expression) { Objects.requireNonNull(expression, "expression must not be null."); final Deque<T> stack = new ArrayDeque<>(); diff --git a/src/main/java/sevenUnits/utils/ObjectProduct.java b/src/main/java/sevenUnits/utils/ObjectProduct.java index 1dacb7d..5b1b739 100644 --- a/src/main/java/sevenUnits/utils/ObjectProduct.java +++ b/src/main/java/sevenUnits/utils/ObjectProduct.java @@ -27,8 +27,8 @@ import java.util.Set; import java.util.function.Function; /** - * An immutable product of multiple objects of a type, such as base units. The objects can be multiplied and - * exponentiated. + * An immutable product of multiple objects of a type, such as base units. The + * objects can be multiplied and exponentiated. * * @author Adrien Hopkins * @since 2019-10-16 @@ -37,38 +37,35 @@ public final class ObjectProduct<T> { /** * Returns an empty ObjectProduct of a certain type * - * @param <T> - * type of objects that can be multiplied + * @param <T> type of objects that can be multiplied * @return empty product * @since 2019-10-16 */ public static final <T> ObjectProduct<T> empty() { return new ObjectProduct<>(new HashMap<>()); } - + /** * Gets an {@code ObjectProduct} from an object-to-integer mapping * - * @param <T> - * type of object in product - * @param map - * map mapping objects to exponents + * @param <T> type of object in product + * @param map map mapping objects to exponents * @return object product * @since 2019-10-16 */ - public static final <T> ObjectProduct<T> fromExponentMapping(final Map<T, Integer> map) { + public static final <T> ObjectProduct<T> fromExponentMapping( + final Map<T, Integer> map) { return new ObjectProduct<>(new HashMap<>(map)); } - + /** - * Gets an ObjectProduct that has one of the inputted argument, and nothing else. + * Gets an ObjectProduct that has one of the inputted argument, and nothing + * else. * - * @param object - * object that will be in the product + * @param object object that will be in the product * @return product * @since 2019-10-16 - * @throws NullPointerException - * if object is null + * @throws NullPointerException if object is null */ public static final <T> ObjectProduct<T> oneOf(final T object) { Objects.requireNonNull(object, "object must not be null."); @@ -76,35 +73,34 @@ public final class ObjectProduct<T> { map.put(object, 1); return new ObjectProduct<>(map); } - + /** - * The objects that make up the product, mapped to their exponents. This map treats zero as null, and is immutable. + * The objects that make up the product, mapped to their exponents. This map + * treats zero as null, and is immutable. * * @since 2019-10-16 */ final Map<T, Integer> exponents; - + /** * Creates the {@code ObjectProduct}. * - * @param exponents - * objects that make up this product + * @param exponents objects that make up this product * @since 2019-10-16 */ private ObjectProduct(final Map<T, Integer> exponents) { - this.exponents = Collections.unmodifiableMap(ConditionalExistenceCollections.conditionalExistenceMap(exponents, - e -> !Integer.valueOf(0).equals(e.getValue()))); + this.exponents = Collections.unmodifiableMap( + ConditionalExistenceCollections.conditionalExistenceMap(exponents, + e -> !Integer.valueOf(0).equals(e.getValue()))); } - + /** * Calculates the quotient of two products * - * @param other - * other product + * @param other other product * @return quotient of two products * @since 2019-10-16 - * @throws NullPointerException - * if other is null + * @throws NullPointerException if other is null */ public ObjectProduct<T> dividedBy(final ObjectProduct<T> other) { Objects.requireNonNull(other, "other must not be null."); @@ -112,17 +108,17 @@ public final class ObjectProduct<T> { final Set<T> objects = new HashSet<>(); objects.addAll(this.getBaseSet()); objects.addAll(other.getBaseSet()); - + // get a list of all exponents final Map<T, Integer> map = new HashMap<>(objects.size()); for (final T key : objects) { map.put(key, this.getExponent(key) - other.getExponent(key)); } - + // create the product return new ObjectProduct<>(map); } - + // this method relies on the use of ZeroIsNullMap @Override public boolean equals(final Object obj) { @@ -133,7 +129,7 @@ public final class ObjectProduct<T> { final ObjectProduct<?> other = (ObjectProduct<?>) obj; return Objects.equals(this.exponents, other.exponents); } - + /** * @return immutable map mapping objects to exponents * @since 2019-10-16 @@ -141,30 +137,31 @@ public final class ObjectProduct<T> { public Map<T, Integer> exponentMap() { return this.exponents; } - + /** - * @return a set of all of the base objects with non-zero exponents that make up this dimension. + * @return a set of all of the base objects with non-zero exponents that make + * up this dimension. * @since 2018-12-12 * @since v0.1.0 */ public final Set<T> getBaseSet() { final Set<T> dimensions = new HashSet<>(); - - // add all dimensions with a nonzero exponent - zero exponents shouldn't be there in the first place + + // add all dimensions with a nonzero exponent - zero exponents shouldn't + // be there in the first place for (final T dimension : this.exponents.keySet()) { if (!this.exponents.get(dimension).equals(0)) { dimensions.add(dimension); } } - + return dimensions; } - + /** * Gets the exponent for a specific dimension. * - * @param dimension - * dimension to check + * @param dimension dimension to check * @return exponent for that dimension * @since 2018-12-12 * @since v0.1.0 @@ -172,14 +169,15 @@ public final class ObjectProduct<T> { public int getExponent(final T dimension) { return this.exponents.getOrDefault(dimension, 0); } - + @Override public int hashCode() { return Objects.hash(this.exponents); } - + /** - * @return true if this product is a single object, i.e. it has one exponent of one and no other nonzero exponents + * @return true if this product is a single object, i.e. it has one exponent + * of one and no other nonzero exponents * @since 2019-10-16 */ public boolean isSingleObject() { @@ -194,16 +192,14 @@ public final class ObjectProduct<T> { } return oneCount == 1 && !twoOrMore; } - + /** * Multiplies this product by another * - * @param other - * other product + * @param other other product * @return product of two products * @since 2019-10-16 - * @throws NullPointerException - * if other is null + * @throws NullPointerException if other is null */ public ObjectProduct<T> times(final ObjectProduct<T> other) { Objects.requireNonNull(other, "other must not be null."); @@ -211,22 +207,21 @@ public final class ObjectProduct<T> { final Set<T> objects = new HashSet<>(); objects.addAll(this.getBaseSet()); objects.addAll(other.getBaseSet()); - + // get a list of all exponents final Map<T, Integer> map = new HashMap<>(objects.size()); for (final T key : objects) { map.put(key, this.getExponent(key) + other.getExponent(key)); } - + // create the product return new ObjectProduct<>(map); } - + /** * Returns this product, but to an exponent * - * @param exponent - * exponent + * @param exponent exponent * @return result of exponentiation * @since 2019-10-16 */ @@ -237,11 +232,12 @@ public final class ObjectProduct<T> { } return new ObjectProduct<>(map); } - + /** - * Converts this product to a string using the objects' {@link Object#toString()} method. If objects have a long - * toString representation, it is recommended to use {@link #toString(Function)} instead to shorten the returned - * string. + * Converts this product to a string using the objects' + * {@link Object#toString()} method. If objects have a long toString + * representation, it is recommended to use {@link #toString(Function)} + * instead to shorten the returned string. * * <p> * {@inheritDoc} @@ -250,35 +246,38 @@ public final class ObjectProduct<T> { public String toString() { return this.toString(Object::toString); } - + /** - * Converts this product to a string. The objects that make up this product are represented by - * {@code objectToString} + * Converts this product to a string. The objects that make up this product + * are represented by {@code objectToString} * - * @param objectToString - * function to convert objects to strings + * @param objectToString function to convert objects to strings * @return string representation of product * @since 2019-10-16 */ public String toString(final Function<T, String> objectToString) { final List<String> positiveStringComponents = new ArrayList<>(); final List<String> negativeStringComponents = new ArrayList<>(); - + // for each base object that makes up this object, add it and its exponent for (final T object : this.getBaseSet()) { final int exponent = this.exponents.get(object); - if (exponent > 0) { - positiveStringComponents.add(String.format("%s^%d", objectToString.apply(object), exponent)); + if (exponent > 1) { + positiveStringComponents.add(String.format("%s^%d", + objectToString.apply(object), exponent)); + } else if (exponent == 1) { + positiveStringComponents.add(objectToString.apply(object)); } else if (exponent < 0) { - negativeStringComponents.add(String.format("%s^%d", objectToString.apply(object), -exponent)); + negativeStringComponents.add(String.format("%s^%d", + objectToString.apply(object), -exponent)); } } - + final String positiveString = positiveStringComponents.isEmpty() ? "1" : String.join(" * ", positiveStringComponents); final String negativeString = negativeStringComponents.isEmpty() ? "" : " / " + String.join(" * ", negativeStringComponents); - + return positiveString + negativeString; } } diff --git a/src/main/java/sevenUnits/utils/UncertainDouble.java b/src/main/java/sevenUnits/utils/UncertainDouble.java index 8fe4b31..fe41104 100644 --- a/src/main/java/sevenUnits/utils/UncertainDouble.java +++ b/src/main/java/sevenUnits/utils/UncertainDouble.java @@ -36,13 +36,14 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { */ public static final UncertainDouble ZERO = UncertainDouble.of(0, 0); + static final String NUMBER_REGEX = "(\\d+(?:[\\.,]\\d+))"; + /** * A regular expression that can recognize toString forms */ - private static final Pattern TO_STRING = Pattern - .compile("([a-zA-Z_0-9\\.\\,]+)" // a number - // optional "± [number]" - + "(?:\\s*(?:±|\\+-)\\s*([a-zA-Z_0-9\\.\\,]+))?"); + static final Pattern TO_STRING = Pattern.compile(NUMBER_REGEX + // optional "± [number]" + + "(?:\\s*(?:±|\\+-)\\s*" + NUMBER_REGEX + ")?"); /** * Parses a string in the form of {@link UncertainDouble#toString(boolean)} @@ -60,10 +61,14 @@ public final class UncertainDouble implements Comparable<UncertainDouble> { Objects.requireNonNull(s, "s may not be null"); final Matcher matcher = TO_STRING.matcher(s); + if (!matcher.matches()) + throw new IllegalArgumentException( + "Could not parse stirng \"" + s + "\"."); + double value, uncertainty; try { value = Double.parseDouble(matcher.group(1)); - } catch (IllegalStateException | NumberFormatException e) { + } catch (final NumberFormatException e) { throw new IllegalArgumentException( "String " + s + " not in correct format."); } |