I am writing a class to evaluate an arithmetic expression, For now my class can convert an infix expression into postfix, it doesn't support exponents yet.
public class Evaluator {
public Map<String, Operator> mOperators = new HashMap<>();
public Evaluator() {
addOperator(new Operator("+", 1) {
@Override
public BigDecimal eval(BigDecimal a, BigDecimal b) {
return a.add(b);
}
});
addOperator(new Operator("-", 1) {
@Override
public BigDecimal eval(BigDecimal a, BigDecimal b) {
return a.subtract(b);
}
});
addOperator(new Operator("*", 2) {
@Override
public BigDecimal eval(BigDecimal a, BigDecimal b) {
return a.multiply(b);
}
});
addOperator(new Operator("/", 2) {
@Override
public BigDecimal eval(BigDecimal a, BigDecimal b) {
return a.divide(b);
}
});
}
public String toPostfix(String infix) {
Stack<String> operators = new Stack<>();
StringBuilder result = new StringBuilder();
String[] tokens = infix.replaceAll("\\s+", "").split("(?<=[^.a-zA-Z\\d])|(?=[^.a-zA-Z\\d])");
for (String token : tokens) {
if (token.matches("-?\\d+(\\.\\d+)?")) {
result.append(token).append(" ");
} else if (operators.isEmpty() || operators.peek().equals("(") || token.equals("(")) {
operators.push(token);
} else if (token.equals(")")) {
while (!operators.peek().equals("(")) {
result.append(operators.pop()).append(" ");
}
operators.pop();
} else {
while (!operators.isEmpty() && precedence(operators.peek()) >= precedence(token)) {
result.append(operators.pop()).append(" ");
}
operators.push(token);
}
}
while (!operators.isEmpty()) {
result.append(operators.pop()).append(" ");
}
return result.toString().trim();
}
public void addOperator(Operator operator) {
mOperators.put(operator.getSymbol(), operator);
}
private int precedence(String token) {
Operator operator = mOperators.getOrDefault(token, null);
return operator == null ? -1 : operator.getPrecedence();
}
public abstract class Operator {
private final String mSymbol;
private final int mPrecedence;
public Operator(String symbol, int precedence) {
mSymbol = symbol;
mPrecedence = precedence;
}
public abstract BigDecimal eval(BigDecimal a, BigDecimal b);
public String getSymbol() {
return mSymbol;
}
public int getPrecedence() {
return mPrecedence;
}
}
}
My questions are:
- How to deal with negative number, e.g:
(-1) + 2
- Is there any easier or better way to evaluate an arithmetic expression without having to turn it into postfix?
- What can I do to optimize my class and make it better?