use of javax.measure.format.ParserException in project sis by apache.
the class UnitFormat method parseTerm.
/**
* Parses a single unit symbol with its exponent.
* The given symbol shall not contain multiplication or division operator.
*
* @param symbols the complete string specified by the user.
* @param lower index where to begin parsing in the {@code symbols} string.
* @param upper index after the last character to parse in the {@code symbols} string.
* @return the parsed unit symbol (never {@code null}).
* @throws ParserException if a problem occurred while parsing the given symbols.
*/
@SuppressWarnings("fallthrough")
private Unit<?> parseTerm(final CharSequence symbols, final int lower, final int upper) throws ParserException {
final String uom = CharSequences.trimWhitespaces(symbols, lower, upper).toString();
/*
* Check for labels explicitly given by users. Those labels have precedence over the Apache SIS hard-coded
* symbols. If no explicit label was found, check for symbols and names known to this UnitFormat instance.
*/
Unit<?> unit = labelToUnit.get(uom);
if (unit == null) {
unit = getPrefixed(uom);
if (unit == null) {
final int length = uom.length();
if (length == 0) {
return Units.UNITY;
} else {
/*
* If the first character is a digit, presume that the term is a multiplication factor.
* The "*" character is used for raising the number on the left to the power on the right.
* Example: "10*6" is equal to one million.
*
* In principle, spaces are not allowed in unit symbols (in particular, UCUM specifies that
* spaces should not be interpreted as multication operators). However in practice we have
* sometime units written in a form like "100 feet".
*/
final char c = uom.charAt(0);
if (isDigit(c) || isSign(c)) {
final double multiplier;
try {
int s = uom.lastIndexOf(' ');
if (s >= 0) {
final int next = CharSequences.skipLeadingWhitespaces(uom, s, length);
if (next < length && AbstractUnit.isSymbolChar(uom.codePointAt(next))) {
multiplier = Double.parseDouble(uom.substring(0, s));
return parseTerm(uom, s, length).multiply(multiplier);
}
}
// Check standard UCUM symbol first.
s = uom.lastIndexOf(Style.EXPONENT_OR_MULTIPLY);
if (s >= 0 || (s = uom.lastIndexOf(Style.EXPONENT)) >= 0) {
final int base = Integer.parseInt(uom.substring(0, s));
final int exp = Integer.parseInt(uom.substring(s + 1));
multiplier = Math.pow(base, exp);
} else {
multiplier = Double.parseDouble(uom);
}
} catch (NumberFormatException e) {
throw (ParserException) new ParserException(Errors.format(Errors.Keys.UnknownUnit_1, uom), symbols, lower).initCause(e);
}
return Units.UNITY.multiply(multiplier);
}
}
if (length >= 2) {
/*
* If the symbol ends with a digit (normal script or superscript), presume that this is the unit
* exponent. That exponent can be a Unicode character (only one character in current UnitFormat
* implementation) or a number parseable with Integer.parseInt(String).
*/
int power = 1;
int i = length;
char c = uom.charAt(--i);
boolean canApply = false;
if (Characters.isSuperScript(c)) {
c = Characters.toNormalScript(c);
if (isDigit(c)) {
power = c - '0';
canApply = true;
}
} else if (isDigit(c)) {
do {
c = uom.charAt(--i);
if (!isDigit(c)) {
if (!isSign(c))
i++;
try {
power = Integer.parseInt(uom.substring(i));
} catch (NumberFormatException e) {
// Should never happen unless the number is larger than 'int' capacity.
throw (ParserException) new ParserException(Errors.format(Errors.Keys.UnknownUnit_1, uom), symbols, lower + i).initCause(e);
}
canApply = true;
break;
}
} while (i != 0);
}
if (canApply) {
/*
* At this point we have parsed the exponent. Before to parse the raw unit symbol,
* skip the exponent symbol (^, * or **) if any.
*/
i = CharSequences.skipTrailingWhitespaces(uom, 0, i);
if (i != 0) {
switch(uom.charAt(i - 1)) {
case Style.EXPONENT_OR_MULTIPLY:
{
if (i != 1 && uom.charAt(i - 2) == Style.EXPONENT_OR_MULTIPLY)
i--;
// Fallthrough for skipping the next character and whitespaces.
}
case Style.EXPONENT:
{
i = CharSequences.skipTrailingWhitespaces(uom, 0, i - 1);
break;
}
}
}
unit = getPrefixed(uom.substring(CharSequences.skipLeadingWhitespaces(uom, 0, i), i));
if (unit != null) {
return unit.pow(power);
}
}
}
/*
* At this point, we have determined that the label is not a known unit symbol.
* It may be a unit name, in which case the label is not case-sensitive anymore.
*/
unit = fromName(uom);
if (unit == null) {
if (CharSequences.regionMatches(symbols, lower, UNITY, true)) {
return Units.UNITY;
}
throw new ParserException(Errors.format(Errors.Keys.UnknownUnit_1, uom), symbols, lower);
}
}
}
return unit;
}
use of javax.measure.format.ParserException in project sis by apache.
the class Proj4 method createCRS.
/**
* Creates a new CRS from the given {@literal Proj.4} definition string.
* Some examples of definition strings are:
* <ul>
* <li>{@code "+init=epsg:3395 +over"} (see warning below)</li>
* <li>{@code "+proj=latlong +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0"}</li>
* <li>{@code "+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +ellps=WGS84 +towgs84=0,0,0"}</li>
* </ul>
*
* <b>Warning:</b> despite the {@code "epsg"} word, coordinate reference systems created by {@code "+init=epsg:"}
* syntax are not necessarily compliant with EPSG definitions. In particular, the axis order is often different.
* Units of measurement may also differ.
*
* @param definition the Proj.4 definition string.
* @param dimension the number of dimension of the CRS to create (2 or 3).
* @return a CRS created from the given definition string and number of dimensions.
* @throws NullPointerException if the definition string is {@code null}.
* @throws IllegalArgumentException if the definition string is empty or the dimension argument is out of range.
* @throws UnavailableFactoryException if the Proj.4 native library is not available.
* @throws FactoryException if the CRS creation failed for another reason.
*
* @see Proj4Factory#createCoordinateReferenceSystem(String)
*/
public static CoordinateReferenceSystem createCRS(String definition, final int dimension) throws FactoryException {
ArgumentChecks.ensureNonEmpty("definition", definition);
ArgumentChecks.ensureBetween("dimension", 2, 3, dimension);
definition = definition.trim();
try {
return Proj4Factory.INSTANCE.createCRS(definition, dimension >= 3);
} catch (IllegalArgumentException | ParserException e) {
throw new InvalidGeodeticParameterException(canNotParse(definition), e);
} catch (UnsatisfiedLinkError | NoClassDefFoundError e) {
throw new UnavailableFactoryException(unavailable(e), e);
}
}
use of javax.measure.format.ParserException in project sis by apache.
the class Proj4Factory method createCoordinateReferenceSystem.
/**
* Creates a new CRS from the given {@literal Proj.4} definition.
* The {@code "Proj4:"} prefix (ignoring case), if present, is ignored.
*
* <div class="section">Apache SIS extension</div>
* Proj.4 unconditionally requires 3 letters for the {@code "+axis="} parameter — for example {@code "neu"} for
* <cite>North</cite>, <cite>East</cite> and <cite>Up</cite> respectively — regardless the number of dimensions
* in the CRS to create. Apache SIS makes the vertical direction optional:
*
* <ul>
* <li>If the vertical direction is present (as in {@code "neu"}), a three-dimensional CRS is created.</li>
* <li>If the vertical direction is absent (as in {@code "ne"}), a two-dimensional CRS is created.</li>
* </ul>
*
* <div class="note"><b>Examples:</b>
* <ul>
* <li>{@code "+init=epsg:4326"} (<strong>not</strong> equivalent to the standard EPSG::4326 definition)</li>
* <li>{@code "+proj=latlong +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0"} (default to two-dimensional CRS)</li>
* <li>{@code "+proj=latlon +a=6378137.0 +b=6356752.314245179 +pm=0.0 +axis=ne"} (explicitely two-dimensional)</li>
* <li>{@code "+proj=latlon +a=6378137.0 +b=6356752.314245179 +pm=0.0 +axis=neu"} (three-dimensional)</li>
* </ul>
* </div>
*
* @param code the Proj.4 definition of the CRS object to create.
* @return a CRS created from the given definition.
* @throws FactoryException if the CRS object can not be created for the given definition.
*
* @see Proj4#createCRS(String, int)
*/
@Override
public CoordinateReferenceSystem createCoordinateReferenceSystem(String code) throws FactoryException {
code = trimNamespace(code);
boolean hasHeight = false;
/*
* Count the number of axes declared in the "+axis" parameter.
* If there is only two axes, add a 'u' (up) direction even in the two-dimensional case.
* We make this addition because Proj.4 seems to require the 3-letters code in all case.
*/
int offset = code.indexOf(AXIS_ORDER_PARAM);
if (offset >= 0) {
offset += AXIS_ORDER_PARAM.length();
final CharSequence orientation = CharSequences.token(code, offset);
for (int i = orientation.length(); --i >= 0; ) {
final char c = orientation.charAt(i);
hasHeight = (c == 'u' || c == 'd');
if (hasHeight)
break;
}
if (!hasHeight && orientation.length() < 3) {
offset = code.indexOf(orientation.toString(), offset);
if (offset >= 0) {
// Should never be -1, but we are paranoiac.
offset += orientation.length();
code = new StringBuilder(code).insert(offset, 'u').toString();
}
}
}
try {
return createCRS(code, hasHeight);
} catch (IllegalArgumentException | ParserException e) {
throw new InvalidGeodeticParameterException(Proj4.canNotParse(code), e);
} catch (UnsatisfiedLinkError | NoClassDefFoundError e) {
throw new UnavailableFactoryException(Proj4.unavailable(e), e);
}
}
use of javax.measure.format.ParserException in project uom-se by unitsofmeasurement.
the class EBNFUnitFormat method parse.
@Override
protected Unit<? extends Quantity<?>> parse(CharSequence csq, ParsePosition cursor) throws ParserException {
// Parsing reads the whole character sequence from the parse position.
int start = cursor != null ? cursor.getIndex() : 0;
int end = csq.length();
if (end <= start) {
return AbstractUnit.ONE;
}
String source = csq.subSequence(start, end).toString().trim();
if (source.length() == 0) {
return AbstractUnit.ONE;
}
try {
UnitFormatParser parser = new UnitFormatParser(symbolMap, new StringReader(source));
Unit<?> result = parser.parseUnit();
if (cursor != null)
cursor.setIndex(end);
return result;
} catch (TokenException e) {
if (e.currentToken != null) {
cursor.setErrorIndex(start + e.currentToken.endColumn);
} else {
cursor.setErrorIndex(start);
}
throw new ParserException(e);
} catch (TokenMgrError e) {
cursor.setErrorIndex(start);
throw new IllegalArgumentException(e.getMessage());
}
}
use of javax.measure.format.ParserException in project uom-se by unitsofmeasurement.
the class LocalUnitFormat method parse.
public Unit<?> parse(CharSequence csq, ParsePosition cursor) throws ParserException {
// Parsing reads the whole character sequence from the parse position.
int start = cursor.getIndex();
int end = csq.length();
if (end <= start) {
return AbstractUnit.ONE;
}
String source = csq.subSequence(start, end).toString().trim();
if (source.length() == 0) {
return AbstractUnit.ONE;
}
try {
LocalUnitFormatParser parser = new LocalUnitFormatParser(symbolMap, new StringReader(source));
Unit<?> result = parser.parseUnit();
cursor.setIndex(end);
return result;
} catch (TokenException e) {
if (e.currentToken != null) {
cursor.setErrorIndex(start + e.currentToken.endColumn);
} else {
cursor.setErrorIndex(start);
}
// TODO should we throw
throw new IllegalArgumentException(e);
// ParserException here,
// too?
} catch (TokenMgrError e) {
cursor.setErrorIndex(start);
throw new ParserException(e);
}
}
Aggregations