package edu.stanford.nlp.ie.qe; import edu.stanford.nlp.io.IOUtils; import edu.stanford.nlp.ling.tokensregex.Env; import edu.stanford.nlp.util.ErasureUtils; import edu.stanford.nlp.util.Pair; import edu.stanford.nlp.util.logging.Redwood; import java.io.BufferedReader; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; /** * List of units * * @author Angel Chang */ public class Units { public static void registerDerivedUnit(Env env, Class clazz, String derivedType, String suffix, String symbolSuffix) { Field[] fields = clazz.getDeclaredFields(); for (Field field:fields) { boolean isStatic = Modifier.isStatic(field.getModifiers()); boolean isUnit = Unit.class.isAssignableFrom(field.getType()); if (isStatic && isUnit) { try { Unit unit = ErasureUtils.uncheckedCast(field.get(null)); registerDerivedUnit(env, unit, derivedType, suffix, symbolSuffix); } catch (IllegalAccessException ex) { } } } } public static void registerDerivedUnit(Env env, Unit unit, String derivedType, String suffix, String symbolSuffix) { Unit derivedUnit = new Unit(unit.getName() + " " + suffix, unit.getSymbol() + symbolSuffix, derivedType); env.bind(derivedType + "_" + unit.getName().toUpperCase() + "_" + suffix.toUpperCase(), derivedUnit); } public static void registerUnit(Env env, Class clazz) { Field[] fields = clazz.getDeclaredFields(); for (Field field:fields) { boolean isStatic = Modifier.isStatic(field.getModifiers()); boolean isUnit = Unit.class.isAssignableFrom(field.getType()); if (isStatic && isUnit) { try { Unit unit = ErasureUtils.uncheckedCast(field.get(null)); registerUnit(env, unit); } catch (IllegalAccessException ex) { } } } } public static void registerUnit(Env env, Unit unit) { env.bind((unit.getType() + "_" + unit.getName()).toUpperCase(), unit); } public static class MoneyUnit extends Unit { public static final String TYPE = "MONEY"; public MoneyUnit(String name, String symbol) { super(name, symbol, TYPE); } public MoneyUnit(String name, String symbol, Unit defaultUnit, double defaultUnitScale) { super(name, symbol, TYPE, defaultUnit, defaultUnitScale); } public String format(double amount) { // Format to 2 decimal places return symbol + String.format("%.2f", amount); } } public static class Currencies { public static final Unit DOLLAR = new MoneyUnit("dollar", "$"); public static final Unit CENT = new MoneyUnit("cent", "¢", DOLLAR, 0.01); public static final Unit POUND = new MoneyUnit("pound", "\u00A3"); public static final Unit PENNY = new MoneyUnit("penny", "¢", DOLLAR, 0.01); public static final Unit EURO = new MoneyUnit("euro", "\u00AC"); public static final Unit YEN = new MoneyUnit("yen", "\u00A5"); public static final Unit YUAN = new MoneyUnit("yuan", "\u5143"); public static final Unit WON = new MoneyUnit("won", "\u20A9"); private Currencies() {} // constant holder class } public static void registerUnits(Env env, String filename) throws IOException { List<Unit> units = loadUnits(filename); registerUnits(env, units); registerUnit(env, Currencies.class); } public static void registerUnits(Env env, List<Unit> units) { for (Unit unit: units) { registerUnit(env, unit); if ("LENGTH".equals(unit.getType())) { registerDerivedUnit(env, unit, "AREA", "2", "2"); registerDerivedUnit(env, unit, "VOLUME", "3", "3"); } } } public static List<Unit> loadUnits(String filename) throws IOException { Pattern commaPattern = Pattern.compile("\\s*,\\s*"); BufferedReader br = IOUtils.getBufferedFileReader(filename); String headerString = br.readLine(); String[] header = commaPattern.split(headerString); Map<String,Integer> headerIndex = new HashMap<>(); for (int i = 0; i < header.length; i++) { headerIndex.put(header[i], i); } int iName = headerIndex.get("unit"); int iPrefix = headerIndex.get("prefix"); int iSymbol = headerIndex.get("symbol"); int iType = headerIndex.get("type"); int iSystem = headerIndex.get("system"); int iDefaultUnit = headerIndex.get("defaultUnit"); int iDefaultUnitScale = headerIndex.get("defaultUnitScale"); String line; List<Unit> list = new ArrayList<>(); Map<String,Unit> unitsByName = new HashMap<>(); Map<String,Pair<String,Double>> unitToDefaultUnits = new HashMap<>(); while ((line = br.readLine()) != null) { String[] fields = commaPattern.split(line); Unit unit = new Unit(fields[iName], fields[iSymbol], fields[iType].toUpperCase()); unit.system = fields[iSystem]; if (fields.length > iPrefix) { unit.prefixSystem = fields[iPrefix]; } if (fields.length > iDefaultUnit) { double scale = 1.0; if (fields.length > iDefaultUnitScale) { scale = Double.parseDouble(fields[iDefaultUnitScale]); } unitToDefaultUnits.put(unit.getName(), Pair.makePair(fields[iDefaultUnit], scale)); } unitsByName.put(unit.getName(), unit); list.add(unit); } for (Map.Entry<String, Pair<String,Double>> entry: unitToDefaultUnits.entrySet()) { Unit unit = unitsByName.get(entry.getKey()); Unit defaultUnit = unitsByName.get(entry.getValue().first); if (defaultUnit != null) { unit.defaultUnit = defaultUnit; unit.defaultUnitScale = entry.getValue().second; } else { Redwood.Util.warn("Unknown default unit " + entry.getValue().first + " for " + entry.getKey()); } } br.close(); return list; } }