From bff8f363ce5e2ca84da1d57a470f0648c4b338e6 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Tue, 26 Nov 2019 20:53:27 -0500 Subject: Prefixes can now have names. --- src/org/unitConverter/math/ObjectProduct.java | 4 +- src/org/unitConverter/unit/LinearUnit.java | 26 ++- src/org/unitConverter/unit/NameSymbol.java | 277 ++++++++++++++++++++++++++ src/org/unitConverter/unit/SI.java | 1 - src/org/unitConverter/unit/Unit.java | 217 -------------------- src/org/unitConverter/unit/UnitDatabase.java | 3 +- src/org/unitConverter/unit/UnitPrefix.java | 85 +++++++- 7 files changed, 388 insertions(+), 225 deletions(-) create mode 100644 src/org/unitConverter/unit/NameSymbol.java (limited to 'src') diff --git a/src/org/unitConverter/math/ObjectProduct.java b/src/org/unitConverter/math/ObjectProduct.java index 29d0f6e..bf00647 100644 --- a/src/org/unitConverter/math/ObjectProduct.java +++ b/src/org/unitConverter/math/ObjectProduct.java @@ -92,8 +92,8 @@ public final class ObjectProduct { * @since 2019-10-16 */ private ObjectProduct(final Map exponents) { - this.exponents = Collections.unmodifiableMap(ConditionalExistenceCollections - .conditionalExistenceMap(new HashMap<>(exponents), e -> !Integer.valueOf(0).equals(e.getValue()))); + this.exponents = Collections.unmodifiableMap(ConditionalExistenceCollections.conditionalExistenceMap(exponents, + e -> !Integer.valueOf(0).equals(e.getValue()))); } /** diff --git a/src/org/unitConverter/unit/LinearUnit.java b/src/org/unitConverter/unit/LinearUnit.java index 1532fc4..1e5ae53 100644 --- a/src/org/unitConverter/unit/LinearUnit.java +++ b/src/org/unitConverter/unit/LinearUnit.java @@ -350,14 +350,38 @@ public final class LinearUnit extends Unit { /** * Returns the result of applying {@code prefix} to this unit. + *

+ * If this unit and the provided prefix have a primary name, the returned unit will have a primary name (prefix's + * name + unit's name).
+ * If this unit and the provided prefix have a symbol, the returned unit will have a symbol.
+ * This method ignores alternate names of both this unit and the provided prefix. * * @param prefix * prefix to apply * @return unit with prefix * @since 2019-03-18 * @since v0.2.0 + * @throws NullPointerException + * if prefix is null */ public LinearUnit withPrefix(final UnitPrefix prefix) { - return this.times(prefix.getMultiplier()); + final LinearUnit unit = this.times(prefix.getMultiplier()); + + // create new name and symbol, if possible + final String name; + if (this.getPrimaryName().isPresent() && prefix.getPrimaryName().isPresent()) { + name = prefix.getPrimaryName().get() + this.getPrimaryName().get(); + } else { + name = null; + } + + final String symbol; + if (this.getSymbol().isPresent() && prefix.getSymbol().isPresent()) { + symbol = prefix.getSymbol().get() + this.getSymbol().get(); + } else { + symbol = null; + } + + return unit.withName(NameSymbol.ofNullable(name, symbol)); } } diff --git a/src/org/unitConverter/unit/NameSymbol.java b/src/org/unitConverter/unit/NameSymbol.java new file mode 100644 index 0000000..96fab45 --- /dev/null +++ b/src/org/unitConverter/unit/NameSymbol.java @@ -0,0 +1,277 @@ +/** + * Copyright (C) 2019 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.unitConverter.unit; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +/** + * A class that can be used to specify names and a symbol for a unit. + * + * @author Adrien Hopkins + * @since 2019-10-21 + */ +public final class NameSymbol { + public static final NameSymbol EMPTY = new NameSymbol(Optional.empty(), Optional.empty(), new HashSet<>()); + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and no other names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if name or symbol is null + */ + public static final NameSymbol of(final String name, final String symbol) { + return new NameSymbol(Optional.of(name), Optional.of(symbol), new HashSet<>()); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final Set otherNames) { + return new NameSymbol(Optional.of(name), Optional.of(symbol), + new HashSet<>(Objects.requireNonNull(otherNames, "otherNames must not be null."))); + } + + /** + * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String... otherNames) { + return new NameSymbol(Optional.of(name), Optional.of(symbol), + new HashSet<>(Arrays.asList(Objects.requireNonNull(otherNames, "otherNames must not be null.")))); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and an additional name. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @param name2 + * alternate name + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String name2) { + final Set otherNames = new HashSet<>(); + otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); + return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @param name2 + * alternate name + * @param name3 + * alternate name + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String name2, final String name3) { + final Set otherNames = new HashSet<>(); + otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); + otherNames.add(Objects.requireNonNull(name3, "name3 must not be null.")); + return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @param name2 + * alternate name + * @param name3 + * alternate name + * @param name4 + * alternate name + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if any argument is null + */ + public static final NameSymbol of(final String name, final String symbol, final String name2, final String name3, + final String name4) { + final Set otherNames = new HashSet<>(); + otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); + otherNames.add(Objects.requireNonNull(name3, "name3 must not be null.")); + otherNames.add(Objects.requireNonNull(name4, "name4 must not be null.")); + return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); + } + + /** + * Gets a {@code NameSymbol} with a primary name, no symbol, and no other names. + * + * @param name + * name to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if name is null + */ + public static final NameSymbol ofName(final String name) { + return new NameSymbol(Optional.of(name), Optional.empty(), new HashSet<>()); + } + + /** + * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + *

+ * If any argument is null, this static factory replaces it with an empty Optional or empty Set. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @return NameSymbol instance + * @since 2019-11-26 + */ + public static final NameSymbol ofNullable(final String name, final String symbol, final Set otherNames) { + return new NameSymbol(Optional.ofNullable(name), Optional.ofNullable(symbol), + otherNames == null ? new HashSet<>() : new HashSet<>(otherNames)); + } + + /** + * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. + *

+ * If any argument is null, this static factory replaces it with an empty Optional or empty Set. + * + * @param name + * name to use + * @param symbol + * symbol to use + * @param otherNames + * other names to use + * @return NameSymbol instance + * @since 2019-11-26 + */ + public static final NameSymbol ofNullable(final String name, final String symbol, final String... otherNames) { + return new NameSymbol(Optional.ofNullable(name), Optional.ofNullable(symbol), + otherNames == null ? new HashSet<>() : new HashSet<>(Arrays.asList(otherNames))); + } + + /** + * Gets a {@code NameSymbol} with a symbol and no names. + * + * @param symbol + * symbol to use + * @return NameSymbol instance + * @since 2019-10-21 + * @throws NullPointerException + * if symbol is null + */ + public static final NameSymbol ofSymbol(final String symbol) { + return new NameSymbol(Optional.empty(), Optional.of(symbol), new HashSet<>()); + } + + private final Optional primaryName; + private final Optional symbol; + + private final Set otherNames; + + /** + * Creates the {@code NameSymbol}. + * + * @param primaryName + * primary name of unit + * @param symbol + * symbol used to represent unit + * @param otherNames + * other names and/or spellings + * @since 2019-10-21 + */ + private NameSymbol(final Optional primaryName, final Optional symbol, + final Set otherNames) { + this.primaryName = primaryName; + this.symbol = symbol; + this.otherNames = Collections.unmodifiableSet(otherNames); + } + + /** + * @return otherNames + * @since 2019-10-21 + */ + public final Set getOtherNames() { + return this.otherNames; + } + + /** + * @return primaryName + * @since 2019-10-21 + */ + public final Optional getPrimaryName() { + return this.primaryName; + } + + /** + * @return symbol + * @since 2019-10-21 + */ + public final Optional getSymbol() { + return this.symbol; + } +} \ No newline at end of file diff --git a/src/org/unitConverter/unit/SI.java b/src/org/unitConverter/unit/SI.java index 19d63e6..c8d228c 100644 --- a/src/org/unitConverter/unit/SI.java +++ b/src/org/unitConverter/unit/SI.java @@ -17,7 +17,6 @@ package org.unitConverter.unit; import org.unitConverter.math.ObjectProduct; -import org.unitConverter.unit.Unit.NameSymbol; /** * All of the units, prefixes and dimensions that are used by the SI, as well as some outside the SI. diff --git a/src/org/unitConverter/unit/Unit.java b/src/org/unitConverter/unit/Unit.java index 737802a..35b32fc 100644 --- a/src/org/unitConverter/unit/Unit.java +++ b/src/org/unitConverter/unit/Unit.java @@ -16,7 +16,6 @@ */ package org.unitConverter.unit; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -35,222 +34,6 @@ import org.unitConverter.math.ObjectProduct; * @since 2019-10-16 */ public abstract class Unit { - /** - * A class that can be used to specify names and a symbol for a unit. - * - * @author Adrien Hopkins - * @since 2019-10-21 - */ - public static final class NameSymbol { - public static final NameSymbol EMPTY = new NameSymbol(Optional.empty(), Optional.empty(), new HashSet<>()); - - /** - * Gets a {@code NameSymbol} with a primary name, a symbol and no other names. - * - * @param name - * name to use - * @param symbol - * symbol to use - * @return NameSymbol instance - * @since 2019-10-21 - * @throws NullPointerException - * if name or symbol is null - */ - public static final NameSymbol of(final String name, final String symbol) { - return new NameSymbol(Optional.of(name), Optional.of(symbol), new HashSet<>()); - } - - /** - * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. - * - * @param name - * name to use - * @param symbol - * symbol to use - * @param otherNames - * other names to use - * @return NameSymbol instance - * @since 2019-10-21 - * @throws NullPointerException - * if any argument is null - */ - public static final NameSymbol of(final String name, final String symbol, final Set otherNames) { - return new NameSymbol(Optional.of(name), Optional.of(symbol), - new HashSet<>(Objects.requireNonNull(otherNames, "otherNames must not be null."))); - } - - /** - * h * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. - * - * @param name - * name to use - * @param symbol - * symbol to use - * @param otherNames - * other names to use - * @return NameSymbol instance - * @since 2019-10-21 - * @throws NullPointerException - * if any argument is null - */ - public static final NameSymbol of(final String name, final String symbol, final String... otherNames) { - return new NameSymbol(Optional.of(name), Optional.of(symbol), - new HashSet<>(Arrays.asList(Objects.requireNonNull(otherNames, "otherNames must not be null.")))); - } - - /** - * Gets a {@code NameSymbol} with a primary name, a symbol and an additional name. - * - * @param name - * name to use - * @param symbol - * symbol to use - * @param otherNames - * other names to use - * @param name2 - * alternate name - * @return NameSymbol instance - * @since 2019-10-21 - * @throws NullPointerException - * if any argument is null - */ - public static final NameSymbol of(final String name, final String symbol, final String name2) { - final Set otherNames = new HashSet<>(); - otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); - return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); - } - - /** - * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. - * - * @param name - * name to use - * @param symbol - * symbol to use - * @param otherNames - * other names to use - * @param name2 - * alternate name - * @param name3 - * alternate name - * @return NameSymbol instance - * @since 2019-10-21 - * @throws NullPointerException - * if any argument is null - */ - public static final NameSymbol of(final String name, final String symbol, final String name2, - final String name3) { - final Set otherNames = new HashSet<>(); - otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); - otherNames.add(Objects.requireNonNull(name3, "name3 must not be null.")); - return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); - } - - /** - * Gets a {@code NameSymbol} with a primary name, a symbol and additional names. - * - * @param name - * name to use - * @param symbol - * symbol to use - * @param otherNames - * other names to use - * @param name2 - * alternate name - * @param name3 - * alternate name - * @param name4 - * alternate name - * @return NameSymbol instance - * @since 2019-10-21 - * @throws NullPointerException - * if any argument is null - */ - public static final NameSymbol of(final String name, final String symbol, final String name2, - final String name3, final String name4) { - final Set otherNames = new HashSet<>(); - otherNames.add(Objects.requireNonNull(name2, "name2 must not be null.")); - otherNames.add(Objects.requireNonNull(name3, "name3 must not be null.")); - otherNames.add(Objects.requireNonNull(name4, "name4 must not be null.")); - return new NameSymbol(Optional.of(name), Optional.of(symbol), otherNames); - } - - /** - * Gets a {@code NameSymbol} with a primary name, no symbol, and no other names. - * - * @param name - * name to use - * @return NameSymbol instance - * @since 2019-10-21 - * @throws NullPointerException - * if name is null - */ - public static final NameSymbol ofName(final String name) { - return new NameSymbol(Optional.of(name), Optional.empty(), new HashSet<>()); - } - - /** - * Gets a {@code NameSymbol} with a symbol and no names. - * - * @param symbol - * symbol to use - * @return NameSymbol instance - * @since 2019-10-21 - * @throws NullPointerException - * if symbol is null - */ - public static final NameSymbol ofSymbol(final String symbol) { - return new NameSymbol(Optional.empty(), Optional.of(symbol), new HashSet<>()); - } - - private final Optional primaryName; - private final Optional symbol; - - private final Set otherNames; - - /** - * Creates the {@code NameSymbol}. - * - * @param primaryName - * primary name of unit - * @param symbol - * symbol used to represent unit - * @param otherNames - * other names and/or spellings - * @since 2019-10-21 - */ - private NameSymbol(final Optional primaryName, final Optional symbol, - final Set otherNames) { - this.primaryName = primaryName; - this.symbol = symbol; - this.otherNames = Collections.unmodifiableSet(otherNames); - } - - /** - * @return otherNames - * @since 2019-10-21 - */ - public final Set getOtherNames() { - return this.otherNames; - } - - /** - * @return primaryName - * @since 2019-10-21 - */ - public final Optional getPrimaryName() { - return this.primaryName; - } - - /** - * @return symbol - * @since 2019-10-21 - */ - public final Optional getSymbol() { - return this.symbol; - } - } - /** * Returns a unit from its base and the functions it uses to convert to and from its base. * diff --git a/src/org/unitConverter/unit/UnitDatabase.java b/src/org/unitConverter/unit/UnitDatabase.java index 6a89b67..9df34a7 100644 --- a/src/org/unitConverter/unit/UnitDatabase.java +++ b/src/org/unitConverter/unit/UnitDatabase.java @@ -974,12 +974,13 @@ public final class UnitDatabase { */ private static final Map EXPRESSION_REPLACEMENTS = new HashMap<>(); + // add data to expression replacements static { // place brackets around any expression of the form "number unit", with or without the space EXPRESSION_REPLACEMENTS.put(Pattern.compile("((?:-?[1-9]\\d*|0)" // integer + "(?:\\.\\d+)?)" // optional decimal point with numbers after it + "\\s*" // optional space(s) - + "([a-zA-Z]+)" // unit name + + "([a-zA-Z]+)" // any string of letters + "(?!-?\\d)" // no number directly afterwards (avoids matching "1e3") ), "\\($1 $2\\)"); } diff --git a/src/org/unitConverter/unit/UnitPrefix.java b/src/org/unitConverter/unit/UnitPrefix.java index 360b0c1..31cc0b3 100644 --- a/src/org/unitConverter/unit/UnitPrefix.java +++ b/src/org/unitConverter/unit/UnitPrefix.java @@ -16,6 +16,10 @@ */ package org.unitConverter.unit; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + import org.unitConverter.math.DecimalComparison; /** @@ -34,9 +38,40 @@ public final class UnitPrefix { * @since 2019-10-16 */ public static UnitPrefix valueOf(final double multiplier) { - return new UnitPrefix(multiplier); + return new UnitPrefix(multiplier, NameSymbol.EMPTY); + } + + /** + * Gets a {@code UnitPrefix} from a multiplier and a name + * + * @param multiplier + * multiplier of prefix + * @param ns + * name(s) and symbol of prefix + * @return prefix + * @since 2019-10-16 + * @throws NullPointerException + * if ns is null + */ + public static UnitPrefix valueOf(final double multiplier, final NameSymbol ns) { + return new UnitPrefix(multiplier, Objects.requireNonNull(ns, "ns must not be null.")); } + /** + * This prefix's primary name + */ + private final Optional primaryName; + + /** + * This prefix's symbol + */ + private final Optional symbol; + + /** + * Other names and symbols used by this prefix + */ + private final Set otherNames; + /** * The number that this prefix multiplies units by * @@ -51,8 +86,11 @@ public final class UnitPrefix { * @since 2019-01-14 * @since v0.2.0 */ - private UnitPrefix(final double multiplier) { + private UnitPrefix(final double multiplier, final NameSymbol ns) { this.multiplier = multiplier; + this.primaryName = ns.getPrimaryName(); + this.symbol = ns.getSymbol(); + this.otherNames = ns.getOtherNames(); } /** @@ -105,6 +143,30 @@ public final class UnitPrefix { return this.multiplier; } + /** + * @return other names + * @since 2019-11-26 + */ + public final Set getOtherNames() { + return this.otherNames; + } + + /** + * @return primary name + * @since 2019-11-26 + */ + public final Optional getPrimaryName() { + return this.primaryName; + } + + /** + * @return symbol + * @since 2019-11-26 + */ + public final Optional getSymbol() { + return this.symbol; + } + /** * {@inheritDoc} * @@ -158,6 +220,23 @@ public final class UnitPrefix { */ @Override public String toString() { - return String.format("Unit prefix with multiplier %s", this.multiplier); + if (this.primaryName.isPresent()) + return String.format("%s (\u00D7 %s)", this.primaryName.get(), this.multiplier); + else if (this.symbol.isPresent()) + return String.format("%s (\u00D7 %s)", this.symbol.get(), this.multiplier); + else + return String.format("Unit Prefix (\u00D7 %s)", this.multiplier); + } + + /** + * @param ns + * name(s) and symbol to use + * @return copy of this prefix with provided name(s) and symbol + * @since 2019-11-26 + * @throws NullPointerException + * if ns is null + */ + public UnitPrefix withName(final NameSymbol ns) { + return valueOf(this.multiplier, ns); } } -- cgit v1.2.3