package net.mattmccutchen.measurements; import java.util.*; public class Unit { public static final Unit SECOND = new Unit("s" , 1.0, 1, 0, 0, 0, 0, 0); public static final Unit METER = new Unit("m" , 1.0, 0, 1, 0, 0, 0, 0); public static final Unit GRAM = new Unit("g" , 1.0, 0, 0, 1, 0, 0, 0); public static final Unit COULOMB = new Unit("coul", 1.0, 0, 0, 0, 1, 0, 0); public static final Unit KELVIN = new Unit("K" , 1.0, 0, 0, 0, 0, 1, 0); public static final Unit MOLE = new Unit("mol" , 1.0, 0, 0, 0, 0, 0, 1); public static final Unit[] basicUnits = new Unit[] { SECOND, METER, GRAM, COULOMB, KELVIN, MOLE, }; // Don't mutate public static final Unit PERCENT = new Unit("%", 1e-2, 0, 0, 0, 0, 0, 0); public static final Unit NEWTON = new Unit("N", 1e+3,-2, 1, 1, 0, 0, 0); public static final Unit JOULE = new Unit("J", 1e+3,-2, 2, 1, 0, 0, 0); public static final Unit WATT = new Unit("W", 1e+3,-3, 2, 1, 0, 0, 0); public static final Unit VOLT = new Unit("V", 1e+3,-2, 2, 1,-1, 0, 0); public static final Unit AMP = new Unit("A", 1.0 ,-1, 0, 0, 1, 0, 0); public static final Unit LITER = new Unit("L", 1e-3, 0, 3, 0, 0, 0, 0); public static final Unit[] allUnits = new Unit[] { SECOND, METER, GRAM, COULOMB, KELVIN, MOLE, PERCENT, NEWTON, JOULE, WATT, VOLT, AMP, LITER, }; // Don't mutate public final String symbol; public final double factor; public final int[] powers; // Don't mutate private Unit(String symbol, double factor, int... powers) { this.symbol = symbol; this.factor = factor; this.powers = powers; } private static final Map unitsBySymbol; // Don't mutate private static final Map prefixes; // Don't mutate public static Unit lookupBySymbol(String symbol) { Unit u = unitsBySymbol.get(symbol); if (u != null) return u; char pfx = symbol.charAt(0); symbol = symbol.substring(1); u = unitsBySymbol.get(symbol); Double mult1 = prefixes.get(pfx); if (u != null && mult1 != null) return new Unit(symbol, u.factor * mult1, u.powers); return null; } static { unitsBySymbol = new LinkedHashMap(); for (Unit u : allUnits) unitsBySymbol.put(u.symbol, u); prefixes = new LinkedHashMap(); prefixes.put('k', 1e+03); prefixes.put('M', 1e+06); prefixes.put('G', 1e+09); prefixes.put('T', 1e+12); prefixes.put('P', 1e+15); prefixes.put('E', 1e+18); prefixes.put('Z', 1e+21); prefixes.put('Y', 1e+24); prefixes.put('c', 1e-02); prefixes.put('m', 1e-03); prefixes.put('u', 1e-06); // micro -> u: oh well prefixes.put('n', 1e-09); prefixes.put('p', 1e-12); prefixes.put('f', 1e-15); prefixes.put('a', 1e-18); prefixes.put('z', 1e-21); prefixes.put('y', 1e-24); } public static Unit parseUnitString(String ustr) { double fctr = 1; int[] up = new int[Unit.basicUnits.length]; StringTokenizer unitT = new StringTokenizer(ustr, " */", true); boolean invert = false; while (unitT.hasMoreTokens()) { String tok = unitT.nextToken(); if (tok.equals("/")) { invert = !invert; continue; } else if (tok.equals(" ") || tok.equals("*")) continue; int caret = tok.indexOf('^'); String symbol; int power; if (caret == -1) { power = 1; symbol = tok; } else { power = Integer.parseInt(tok.substring(caret + 1)); symbol = tok.substring(0, caret); } Unit unit = Unit.lookupBySymbol(symbol); if (unit == null) throw new NullPointerException(); if (invert) power = -power; fctr *= Math.pow(unit.factor, power); for (int i = 0; i < Unit.basicUnits.length; i++) up[i] += power * unit.powers[i]; } return new Unit(ustr, fctr, up); } }