All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tec.units.ri.format.QuantityFormat Maven / Gradle / Ivy

There is a newer version: 1.0.3
Show newest version
/*
 *  Unit-API - Units of Measurement API for Java
 *  Copyright (c) 2005-2015, Jean-Marie Dautelle, Werner Keil, V2COM.
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package tec.units.ri.format;

import java.io.IOException;

import javax.measure.Quantity;
import javax.measure.Unit;
import javax.measure.format.Parser;
import javax.measure.format.ParserException;
import javax.measure.format.UnitFormat;

import tec.units.ri.AbstractQuantity;
import tec.units.ri.AbstractUnit;
import tec.units.ri.internal.format.l10n.NumberFormat;
import tec.units.ri.quantity.NumberQuantity;
import tec.units.ri.unit.Units;

/**
 * 

This class provides the interface for formatting and parsing {@link AbstractQuantity * measurements}.

* *

Instances of this class should be able to format measurements stated in * {@link CompoundUnit}. See {@link #formatCompound formatCompound(...)}. *

* * @author Jean-Marie Dautelle * @author Werner Keil * @version 0.6.2, $Date: 2015-07-05 $ */ @SuppressWarnings("rawtypes") public abstract class QuantityFormat implements Parser { /** * */ // private static final long serialVersionUID = -4628006924354248662L; /** * Holds the default format instance. */ private static final NumberSpaceUnit DEFAULT = new NumberSpaceUnit( NumberFormat.getInstance(), EBNFUnitFormat.getInstance()); /** * Holds the standard format instance. */ private static final Standard STANDARD = new Standard(); /** * Returns the measure format for the default locale. The default format * assumes the measure is composed of a decimal number and a {@link Unit} * separated by whitespace(s). * * @return MeasureFormat.getInstance(NumberFormat.getInstance(), UnitFormat.getInstance()) */ public static QuantityFormat getInstance() { return DEFAULT; } // /** // * Returns the measure format using the specified number format and unit // * format (the number and unit are separated by one space). // * // * @param numberFormat the number format. // * @param unitFormat the unit format. // * @return the corresponding format. // */ // public static QuantityFormat getInstance(NumberFormat numberFormat, // UnitFormat unitFormat) { // return new NumberSpaceUnit(numberFormat, unitFormat); // } /** * Returns the culture invariant format based upon {@link Number} * canonical format and the {@link UnitFormat#current() standard} unit * format. This format is not locale-sensitive and can be used for * unambiguous electronic communication of quantities together with their * units without loss of information. For example: * "1.23456789 kg.m/s2" returns * Quantities.getQuantity(new Double(1.23456789d), AbstractUnit.parse("kg.m/s2"))); * * @param style the format style to apply. * @return the desired format. */ public static QuantityFormat getInstance(FormatBehavior style) { switch (style) { case LOCALE_NEUTRAL: return STANDARD; case LOCALE_SENSITIVE: return DEFAULT; default: return DEFAULT; } } /** * Formats the specified measure into an Appendable. * * @param measure the measure to format. * @param dest the appendable destination. * @return the specified Appendable. * @throws IOException if an I/O exception occurs. */ public abstract Appendable format(AbstractQuantity measure, Appendable dest) throws IOException; /** * Parses a portion of the specified CharSequence from the * specified position to produce an object. If parsing succeeds, then the * index of the cursor argument is updated to the index after * the last character used. * * @param csq the CharSequence to parse. * @param index the current parsing index. * @return the object parsed from the specified character sub-sequence. * @throws IllegalArgumentException * if any problem occurs while parsing the specified character * sequence (e.g. illegal syntax). */ abstract AbstractQuantity parse(CharSequence csq, int index) throws IllegalArgumentException, ParserException; /** * Parses a portion of the specified CharSequence from the * specified position to produce an object. If parsing succeeds, then the * index of the cursor argument is updated to the index after * the last character used. * * @param csq the CharSequence to parse. * @param cursor the cursor holding the current parsing index. * @return the object parsed from the specified character sub-sequence. * @throws IllegalArgumentException * if any problem occurs while parsing the specified character * sequence (e.g. illegal syntax). */ /*public abstract AbstractQuantity parse(CharSequence csq) throws IllegalArgumentException, ParserException; */ /** * Formats the specified value using {@link CompoundUnit} compound units}. * The default implementation is locale sensitive and does not use space to * separate units. For example:[code] * Unit FOOT_INCH = FOOT.compound(INCH); * Measure height = Measure.valueOf(1.81, METER); * System.out.println(height.to(FOOT_INCH)); * * > 5ft11,26in // French Local * * Unit DMS = DEGREE_ANGLE.compound(MINUTE_ANGLE).compound(SECOND_ANGLE); * Measure rotation = Measure.valueOf(35.857497, DEGREE_ANGLE); * System.out.println(rotation.to(DMS)); * * > 35°51'26,989" // French Local * [/code] * * @param value the value to format using compound units. * @param unit the compound unit. * @param dest the appendable destination. * @return the specified Appendable. * @throws IOException if an I/O exception occurs. */ // @SuppressWarnings("unchecked") // protected Appendable formatCompound(double value, CompoundUnit unit, // Appendable dest) throws IOException { // Unit high = unit.getHigh(); // Unit low = unit.getLow(); // The unit in which the value is stated. // long highValue = (long) low.getConverterTo(high).convert(value); // double lowValue = value - high.getConverterTo(low).convert(highValue); // if (high instanceof CompoundUnit) // formatCompound(highValue, (CompoundUnit) high, dest); // else { // dest.append(DEFAULT._numberFormat.format(highValue)); // DEFAULT._unitFormat.format(high, dest); // } // dest.append(DEFAULT._numberFormat.format(lowValue)); // return DEFAULT._unitFormat.format(low, dest); // } /* public final StringBuffer format(Object obj, final StringBuffer toAppendTo, FieldPosition pos) { if (!(obj instanceof AbstractQuantity)) throw new IllegalArgumentException( "obj: Not an instance of Measure"); if ((toAppendTo == null) || (pos == null)) throw new NullPointerException(); try { return (StringBuffer) format((AbstractQuantity) obj, (Appendable) toAppendTo); } catch (IOException ex) { throw new Error(ex); // Cannot happen. } } */ /* final AbstractQuantity parseObject(String source, ParsePosition pos) { try { return parse(source, pos); } catch (IllegalArgumentException | ParserException e) { return null; // Unfortunately the message why the parsing failed } // is lost; but we have to follow the Format spec. } */ /** * Convenience method equivalent to {@link #format(AbstractQuantity, Appendable)} * except it does not raise an IOException. * * @param measure the measure to format. * @param dest the appendable destination. * @return the specified StringBuilder. */ public final StringBuilder format(AbstractQuantity measure, StringBuilder dest) { try { return (StringBuilder) this.format(measure, (Appendable) dest); } catch (IOException ex) { throw new RuntimeException(ex); // Should not happen. } } // Holds default implementation. private static final class NumberSpaceUnit extends QuantityFormat { private final NumberFormat numberFormat; private final UnitFormat unitFormat; private NumberSpaceUnit(NumberFormat numberFormat, UnitFormat unitFormat) { this.numberFormat = numberFormat; this.unitFormat = unitFormat; } @Override public Appendable format(AbstractQuantity quantity, Appendable dest) throws IOException { // Unit unit = measure.getUnit(); // if (unit instanceof CompoundUnit) // return formatCompound(measure.doubleValue(unit), // (CompoundUnit) unit, dest); // else { dest.append(numberFormat.format(quantity.getValue())); if (quantity.getUnit().equals(Units.ONE)) return dest; dest.append(' '); return unitFormat.format(quantity.getUnit(), dest); // } } @SuppressWarnings("unchecked") @Override AbstractQuantity parse(CharSequence csq, int index) throws IllegalArgumentException, ParserException { String str = csq.toString(); Number number = numberFormat.parse(str); if (number == null) throw new IllegalArgumentException("Number cannot be parsed"); Unit unit = unitFormat.parse(csq); if (number instanceof Long) return NumberQuantity.of(number.longValue(), unit); else if (number instanceof Double) return NumberQuantity.of(number.doubleValue(), unit); else if (number instanceof Integer) return NumberQuantity.of(number.intValue(), unit); else throw new UnsupportedOperationException("Number of type " + number.getClass() + " are not supported"); } public AbstractQuantity parse(CharSequence csq) throws IllegalArgumentException, ParserException { return parse(csq, 0); } // private static final long serialVersionUID = 1L; } // Holds standard implementation. private static final class Standard extends QuantityFormat { /** * */ // private static final long serialVersionUID = 2758248665095734058L; @Override public Appendable format(AbstractQuantity measure, Appendable dest) throws IOException { Unit unit = measure.getUnit(); // if (unit instanceof CompoundUnit) // return formatCompound(measure.doubleValue(unit), // (CompoundUnit) unit, dest); // else { // if (measure.isBig()) { // TODO SE only // BigDecimal decimal = measure.decimalValue(unit, // MathContext.UNLIMITED); // dest.append(decimal.toString()); // } else { Number number = measure.getValue(); dest.append(number.toString()); // } if (measure.getUnit().equals(Units.ONE)) return dest; dest.append(' '); return EBNFUnitFormat.getInstance().format(unit, dest); // } } @SuppressWarnings("unchecked") @Override AbstractQuantity parse(CharSequence csq, int index) throws ParserException { int startDecimal = index; //cursor.getIndex(); while ((startDecimal < csq.length()) && Character.isWhitespace(csq.charAt(startDecimal))) { startDecimal++; } int endDecimal = startDecimal + 1; while ((endDecimal < csq.length()) && !Character.isWhitespace(csq.charAt(endDecimal))) { endDecimal++; } Double decimal = new Double(csq.subSequence(startDecimal, endDecimal).toString()); // cursor.setIndex(endDecimal + 1); Unit unit = EBNFUnitFormat.getInstance().parse(csq, index); return NumberQuantity.of(decimal.doubleValue(), unit); } public AbstractQuantity parse(CharSequence csq) throws ParserException { return parse(csq, 0); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy