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

com.hwaipy.quantity.QuantityParser Maven / Gradle / Ivy

The newest version!
package com.hwaipy.quantity;

/**
 * @author Hwaipy 2015-3-17
 */
class QuantityParser {

  private final String quantityString;

  public QuantityParser(String quantityString) {
    this.quantityString = quantityString;
  }

  public Quantity parse() throws QuantityParseException {
    Quantity quantity = tryExtractQuantity();
    if (position < quantityString.length()) {
      throw new QuantityParseException();
    }
    return quantity;
  }

  public Unit parseUnit(boolean withFactor) throws QuantityParseException {
    double factor = 1;
    if (withFactor) {
      factor = tryExtractNumber();
      if (Double.isNaN(factor)) {
        factor = 1;
      }
    }
    Unit unit = tryExtractUnit();
    return new UnitBuilder(unit).times(factor).createUnit();
  }

  private int position = 0;

  public double tryExtractNumber() {
    int p0 = position;
    String integralString = tryExtractInteger(true);
    String mantissaString = null;
    String powerString = null;
    if (isNext('.')) {
      position++;
      mantissaString = tryExtractInteger(false);
    }
    if (integralString.length() == 0 || (integralString.length() == 1 && ("+".equals(integralString) || "-".equals(integralString)))) {
      if (mantissaString == null || mantissaString.length() == 0) {
        position = p0;
        return Double.NaN;
      }
    }
    String valueString = integralString;
    int p1 = position;
    if (isNext('e') || isNext('E')) {
      position++;
      powerString = tryExtractInteger(true);
    }
    if (mantissaString != null) {
      valueString += "." + mantissaString;
    }
    if (powerString == null) {
      return Double.parseDouble(valueString);
    }
    else if (powerString.length() == 0 || (powerString.length() == 1 && ("+".equals(powerString) || "-".equals(powerString)))) {
      position = p1;
      return Double.parseDouble(valueString);
    }
    else {
      return Double.parseDouble(valueString + "E" + powerString);
    }
  }

  public Unit tryExtractUnit() {
    UnitBuilder unitBuilder = new UnitBuilder();
    while (position < quantityString.length()) {
      trim();
      int p = position;
      boolean powerUp = true;
      char c = quantityString.charAt(position);
      if (c == '/') {
        powerUp = false;
        position++;
      }
      else if (c == '.' || c == '*' || c == '⋅' || c == '×') {
        position++;
      }
      Unit unit = tryExtractOneUnit();
      if (unit == null) {
        position = p;
        break;
      }
      else {
        if (powerUp) {
          unitBuilder.times(unit);
        }
        else {
          unitBuilder.divide(unit);
        }
      }
    }
    return unitBuilder.createUnit();
  }

  public Quantity tryExtractQuantity() {
    double value = tryExtractNumber();
    if (Double.isNaN(value)) {
      return null;
    }
    Unit unit = tryExtractUnit();
    return new Quantity(value, unit);
  }

  public String restString() {
    return quantityString.substring(position);
  }

  private String tryExtractInteger(boolean withSign) {
    StringBuilder sb = new StringBuilder();
    while (position < quantityString.length()) {
      char c = quantityString.charAt(position);
      if (c == '+' || c == '-') {
        if (withSign && sb.length() == 0) {
          position++;
          sb.append(c);
        }
        else {
          break;
        }
      }
      else if (c == ',' || c == ' ' || c == '\t') {
        position++;
      }
      else {
        char digit = digit(c);
        if (digit > 0) {
          position++;
          sb.append(digit);
        }
        else {
          break;
        }
      }
    }
    return sb.toString();
  }

  private boolean isNext(char target) {
    if (position < quantityString.length()) {
      char c = quantityString.charAt(position);
      return c == target;
    }
    else {
      return false;
    }
  }

  private char digit(char c) {
    if (c >= '0' && c <= '9') {
      return c;
    }
    else if (c >= '0' && c <= '9') {
      return (char) (c - ('0' - '0'));
    }
    else {
      return 0;
    }
  }

  private Unit tryExtractOneUnit() {
    int p0 = position;
    String token = tryExtractOneToken();
    if (token.length() == 0) {
      position = p0;
      return null;
    }
    else {
      Unit baseUnit = tryParseOneUnit(token);
      if (baseUnit == null) {
        position = p0;
        return null;
      }
      else {
        if (isNext('^')) {
          int p1 = position;
          position++;
          String powerString = tryExtractInteger(true);
          if (powerString.length() == 0 || (powerString.length() == 1 && ("+".equals(powerString) || "-".equals(powerString)))) {
            position = p1;
            return baseUnit;
          }
          else {
            int power = Integer.parseInt(powerString);
            return baseUnit.power(power);
          }
        }
        else {
          return baseUnit;
        }
      }
    }
  }

  private void trim() {
    while (position < quantityString.length()) {
      char c = quantityString.charAt(position);
      if (c == ' ' || c == '\t') {
        position++;
      }
      else {
        break;
      }
    }
  }

  private String tryExtractOneToken() {
    StringBuilder sb = new StringBuilder();
    while (position < quantityString.length()) {
      char c = quantityString.charAt(position);
      if (c == ' ' || c == '\t' || c == '+' || c == '-' || c == ',' || c == '.'
              || c == '*' || c == '⋅' || c == '×' || c == '/' || c == '^') {
      }
      else {
        switch (Character.getType(c)) {
          case Character.COMBINING_SPACING_MARK:
          case Character.CONNECTOR_PUNCTUATION:
          case Character.CURRENCY_SYMBOL:
          case Character.DASH_PUNCTUATION:
          case Character.ENCLOSING_MARK:
          case Character.START_PUNCTUATION:
          case Character.END_PUNCTUATION:
          case Character.FINAL_QUOTE_PUNCTUATION:
          case Character.FORMAT:
          case Character.INITIAL_QUOTE_PUNCTUATION:
          case Character.LETTER_NUMBER:
          case Character.LOWERCASE_LETTER:
          case Character.MATH_SYMBOL:
          case Character.MODIFIER_LETTER:
          case Character.MODIFIER_SYMBOL:
          case Character.NON_SPACING_MARK:
          case Character.OTHER_LETTER:
          case Character.OTHER_NUMBER:
          case Character.OTHER_PUNCTUATION:
          case Character.OTHER_SYMBOL:
          case Character.SURROGATE:
          case Character.TITLECASE_LETTER:
          case Character.UPPERCASE_LETTER:
            position++;
            sb.append(c);
            continue;
          default:
        }
      }
      break;
    }
    return sb.toString();
  }

  private Unit tryParseOneUnit(String unitString) {
    for (int split = 0; split < unitString.length(); split++) {
      String prefixString = unitString.substring(0, split);
      String tokenString = unitString.substring(split);
      UnitPrefix prefix = UnitPrefixes.get(prefixString);
      Unit unit = Units.get(tokenString);
      if (prefix != null && unit != null && (prefix == UnitPrefixes.none || unit.hasPrefix())) {
        return unit.prefix(prefix);
      }
    }
    return null;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy