算术表达式计算:Java版本

用Java语言实现的算术表达式计算器

利用两个堆栈,一个保存操作数,一个保存操作符,一边解析输入,一边计算

# Calculator.java 类

import java.util.Stack;

public class Calculator {

  public String eval(String expr) {
    return _eval(expr);
  }

  public static class Lexer {

    private Lexer(String expr) {
      this.input = expr;
      this.seq = expr.toCharArray();
      this.pos = 0;
    }

    public static Lexer create(String expr) {
      return new Lexer(expr);
    }

    public String input;
    public char[] seq;
    int pos;

    public String getWord() {
      StringBuffer ret = new StringBuffer();
      boolean end = false;
      TYPE current = TYPE.NUL;
      while (!end && pos < seq.length) {
        char c = seq[pos];
        switch (c) {
          case '+':
            end = true;
            if (current == TYPE.FLOAT) {
              break;
            }
            current = TYPE.PLUS;
            ret.append(c);
            pos++;
            end = true;
            break;
          case '-':
            end = true;
            if (current == TYPE.FLOAT) {
              break;
            }
            current = TYPE.MINUS;
            ret.append(c);
            pos++;
            end = true;
            break;
          case '*':
            end = true;
            if (current == TYPE.FLOAT) {
              break;
            }
            current = TYPE.MUL;
            ret.append(c);
            pos++;
            end = true;
            break;

          case '/':
            end = true;
            if (current == TYPE.FLOAT) {
              break;
            }
            current = TYPE.DIV;
            ret.append(c);
            pos++;
            end = true;
            break;

          case '(':
            end = true;
            if (current == TYPE.FLOAT) {
              break;
            }
            current = TYPE.L_P;
            ret.append(c);
            pos++;
            end = true;
            break;

          case ')':
            end = true;
            if (current == TYPE.FLOAT) {
              break;
            }
            current = TYPE.R_P;
            ret.append(c);
            pos++;
            break;

          default:
            current = TYPE.FLOAT;
            ret.append(c);
            pos++;
            end = false;
            break;
        }
      }
      return ret.toString();
    }
  }

  int getPrior(TYPE p) {
    if (p == TYPE.PLUS || p == TYPE.MINUS) {
      return 1;
    }
    if (p == TYPE.MUL || p == TYPE.DIV) {
      return 2;
    }
    if (p == TYPE.L_P || p == TYPE.R_P) {
      return 0;
    }
    return -1;
  }

  int getPrior(String p) {
    return getPrior(TYPE.typeOf(p));
  }

  boolean isOp(TYPE t) {
    return getPrior(t) != -1;
  }

  boolean isOp(String s) {
    return isOp(TYPE.typeOf(s));
  }

  enum TYPE {
    PLUS,
    MINUS,
    MUL,
    DIV,
    L_P,
    R_P,
    FLOAT,
    NUL;

    static TYPE typeOf(String word) {
      if ("+".equals(word)) {
        return PLUS;
      }
      if ("-".equals(word)) {
        return MINUS;
      }
      if ("/".equals(word)) {
        return DIV;
      }
      if ("*".equals(word)) {
        return MUL;
      }
      if ("(".equals(word)) {
        return L_P;
      }
      if (")".equals(word)) {
        return R_P;
      }
      if ("".equals(word)) {
        return NUL;
      }
      return FLOAT;
    }
  }

  public String _eval(String expr) {
    Stack<String> numStack = new Stack(), opStack = new Stack();
    Lexer lexer = Lexer.create(expr);
    String word = lexer.getWord();
    while (!"".equals(word)) {
      if (isOp(word)) {
        if (opStack.empty()) {
          opStack.push(word);
        } else {
          if (")".equals(word)) {
            String operator = opStack.pop();
            String right = numStack.pop();
            String left = numStack.pop();
            numStack.push(new Float(op(operator, left, right)).toString());
            opStack.pop(); // 左括号
            if(!opStack.empty()){
              word = opStack.pop();
              continue;
            }
          } else if ("(".equals(word)) {
            opStack.push(word);
          } else {
            String preOp = opStack.peek();
            if (getPrior(word) <= getPrior(preOp)) {
              preOp = opStack.pop();
              String right = numStack.pop();
              String left = numStack.pop();
              numStack.push(new Float(op(preOp, left, right)).toString());
              continue;
            } else {
              opStack.push(word);
            }
          }
        }
      } else {
        numStack.push(word);
      }
      word = lexer.getWord();
      printStack(numStack, opStack);
    }
    while (!opStack.empty()) {
      String right = numStack.pop();
      String left = numStack.pop();
      numStack.push(new Float(op(opStack.pop(), left, right)).toString());
      printStack(numStack, opStack);
    }
    return numStack.pop();
  }

  void printStack(Stack<String> s, Stack<String> s1) {
    for (String ele : s) {
      System.out.print(" " + ele);
    }
    System.out.print("||");
    for (String ele : s1) {
      System.out.print(" " + ele);
    }
    System.out.println();
  }

  public float op(String op, String left, String right) {
    float l = Float.parseFloat(left), r = Float.parseFloat(right);
    if ("+".equals(op)) {
      return l + r;
    }
    if ("-".equals(op)) {
      return l - r;
    }
    if ("/".equals(op)) {
      return 0 == r ? 0 : (l / r);
    }
    if ("*".equals(op)) {
      return l * r;
    }
    return 0;
  }
}

#测试类

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class CalculatorTest {

  Calculator calc = new Calculator();

  @Test
  public void testPlus() {
    assertEquals("2.1", calc.eval("1+1.1"));
  }

  @Test
  public void testParen() {
    assertEquals("5.1", calc.eval("1*(2.1+3)"));
  }

  @Test
  public void testOrder() {
    assertEquals("5.2", calc.eval("2+1*3.2"));
  }

  @Test
  public void testComplex(){
    assertEquals("", "-3.6", calc.eval("2+2-3*4.2+5-(4-3)*(4/5)/0"));
  }

  @Test
  public void testComplex2(){
    assertEquals("", "18.0", calc.eval("(1+2+3+4)*4-(2*3*4-1)+1"));
  }

  @Test
  public void testGetWord() {
    Calculator.Lexer lexer = Calculator.Lexer.create("1+2+3+45.3*(1+2)");
    assertEquals("1", lexer.getWord());
    assertEquals("+", lexer.getWord());
    assertEquals("2", lexer.getWord());
    assertEquals("+", lexer.getWord());
    assertEquals("3", lexer.getWord());
    assertEquals("+", lexer.getWord());
    assertEquals("45.3", lexer.getWord());
    assertEquals("*", lexer.getWord());
    assertEquals("(", lexer.getWord());
    assertEquals("1", lexer.getWord());
    assertEquals("+", lexer.getWord());
    assertEquals("2", lexer.getWord());
    assertEquals(")", lexer.getWord());
    assertEquals("", lexer.getWord());
  }
}

有一个测试案例报错原因是浮点数的精度问题