package com.coding2017.basic.stack.expr; import java.util.Arrays; import java.util.List; import java.util.Stack; import java.util.stream.Collectors; import com.google.common.base.CharMatcher; import com.google.common.collect.Lists; public class InfixExpr { private static final CharMatcher CHAR_MATCHER = CharMatcher.anyOf(Operator.allOperator()); private Stack<String> operatorStack = new Stack<>(); private Stack<Float> numberStack = new Stack<>(); String expr = null; public InfixExpr(String expr) { this.expr = expr; } public float evaluate() { List<String> list = splitByOperator(expr); for (String s : list) { if (Operator.isOperator(s)) { if (operatorStack.isEmpty()) { operatorStack.push(s); } else { while (true) { String op = operatorStack.peek(); if (Operator.opOf(op).getPriority() >= Operator.opOf(s).getPriority()) { calculateOnce(); } else { break; } if (operatorStack.isEmpty()) { break; } } operatorStack.push(s); } } else { numberStack.push(Float.parseFloat(s)); } } while (!operatorStack.isEmpty()) { calculateOnce(); } if (numberStack.isEmpty() || numberStack.size() != 1) { throw new RuntimeException("expr error"); } return numberStack.pop(); } private void calculateOnce() { String operator = operatorStack.pop(); Float secondNumber = numberStack.pop(); Float firstNumber = numberStack.pop(); Float calculate = calculate(firstNumber, secondNumber, operator); numberStack.push(calculate); } private Float calculate(Float firstNumber, Float seconfNumber, String operator) { if (Operator.ADD.getOp().equals(operator)) { return firstNumber + seconfNumber; } else if (Operator.MINUTE.getOp().equals(operator)) { return firstNumber - seconfNumber; } else if (Operator.MULTIPLY.getOp().equals(operator)) { return firstNumber * seconfNumber; } else if (Operator.DIVIDE.getOp().equals(operator)) { return firstNumber / seconfNumber; } return null; } private List<String> splitByOperator(String expr) { int pos = 0; List<String> list = Lists.newArrayList(); while (pos < expr.length()) { int index = CHAR_MATCHER.indexIn(expr, pos); if (index < 0) { list.add(expr.substring(pos).trim()); pos = expr.length(); } else { list.add(expr.substring(pos, index).trim()); list.add(expr.substring(index, index + 1)); pos = index + 1; } } return list; } enum Operator { ADD("+", 1), MINUTE("-", 1), MULTIPLY("*", 2), DIVIDE("/", 2); private String op; private int priority; Operator(String op, int priority) { this.op = op; this.priority = priority; } public static Operator opOf(String op) { for (Operator operator : values()) { if (operator.getOp().equals(op)) { return operator; } } return null; } public static boolean isOperator(String op) { for (Operator operator : values()) { if (operator.getOp().equals(op)) { return true; } } return false; } public static String allOperator() { return Arrays.stream(values()).map(Operator::getOp).collect(Collectors.joining()); } public String getOp() { return op; } public void setOp(String op) { this.op = op; } public int getPriority() { return priority; } public void setPriority(int priority) { this.priority = priority; } } }