|
|
package model;
|
|
|
import java.util.*;
|
|
|
|
|
|
public class ExpressionEvaluator {
|
|
|
|
|
|
private static final Map<String, Integer> PRECEDENCE = new HashMap<>();
|
|
|
static {
|
|
|
PRECEDENCE.put("+", 1);
|
|
|
PRECEDENCE.put("-", 1);
|
|
|
PRECEDENCE.put("*", 2);
|
|
|
PRECEDENCE.put("/", 2);
|
|
|
PRECEDENCE.put("^", 3);
|
|
|
}
|
|
|
|
|
|
// 判断是否是运算符
|
|
|
private static boolean isOperator(String token) {
|
|
|
return PRECEDENCE.containsKey(token);
|
|
|
}
|
|
|
|
|
|
// 运算符优先级
|
|
|
private static int precedence(String op) {
|
|
|
return PRECEDENCE.get(op);
|
|
|
}
|
|
|
|
|
|
// 将中缀表达式转为逆波兰表达式(RPN)
|
|
|
private static List<String> toRPN(String expr) {
|
|
|
List<String> output = new ArrayList<>();
|
|
|
Stack<String> stack = new Stack<>();
|
|
|
|
|
|
// 正则拆分 token(数字、函数、符号、括号)
|
|
|
StringTokenizer tokenizer = new StringTokenizer(expr, "+-*/^() ", true);
|
|
|
while (tokenizer.hasMoreTokens()) {
|
|
|
String token = tokenizer.nextToken().trim();
|
|
|
if (token.isEmpty()) continue;
|
|
|
|
|
|
if (token.matches("[0-9.]+")) { // 数字
|
|
|
output.add(token);
|
|
|
} else if (token.matches("[a-zA-Z]+")) { // 函数
|
|
|
stack.push(token);
|
|
|
} else if (isOperator(token)) { // 运算符
|
|
|
while (!stack.isEmpty() && isOperator(stack.peek())
|
|
|
&& precedence(stack.peek()) >= precedence(token)) {
|
|
|
output.add(stack.pop());
|
|
|
}
|
|
|
stack.push(token);
|
|
|
} else if (token.equals("(")) {
|
|
|
stack.push(token);
|
|
|
} else if (token.equals(")")) {
|
|
|
while (!stack.isEmpty() && !stack.peek().equals("(")) {
|
|
|
output.add(stack.pop());
|
|
|
}
|
|
|
if (!stack.isEmpty() && stack.peek().equals("(")) {
|
|
|
stack.pop();
|
|
|
}
|
|
|
// 如果栈顶是函数,弹出函数
|
|
|
if (!stack.isEmpty() && stack.peek().matches("[a-zA-Z]+")) {
|
|
|
output.add(stack.pop());
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
while (!stack.isEmpty()) {
|
|
|
output.add(stack.pop());
|
|
|
}
|
|
|
|
|
|
return output;
|
|
|
}
|
|
|
|
|
|
// 计算逆波兰表达式
|
|
|
private static double evalRPN(List<String> rpn) {
|
|
|
Stack<Double> stack = new Stack<>();
|
|
|
for (String token : rpn) {
|
|
|
if (token.matches("[0-9.]+")) {
|
|
|
stack.push(Double.parseDouble(token));
|
|
|
} else if (isOperator(token)) {
|
|
|
double b = stack.pop();
|
|
|
double a = stack.pop();
|
|
|
switch (token) {
|
|
|
case "+": stack.push(a + b); break;
|
|
|
case "-": stack.push(a - b); break;
|
|
|
case "*": stack.push(a * b); break;
|
|
|
case "/": stack.push(a / b); break;
|
|
|
case "^": stack.push(Math.pow(a, b)); break;
|
|
|
}
|
|
|
} else { // 函数
|
|
|
double a = stack.pop();
|
|
|
switch (token.toLowerCase()) {
|
|
|
case "sin": stack.push(Math.sin(Math.toRadians(a))); break;
|
|
|
case "cos": stack.push(Math.cos(Math.toRadians(a))); break;
|
|
|
case "tan": stack.push(Math.tan(Math.toRadians(a))); break;
|
|
|
case "sqrt": stack.push(Math.sqrt(a)); break;
|
|
|
default: throw new RuntimeException("未知函数: " + token);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return stack.pop();
|
|
|
}
|
|
|
|
|
|
// 对外接口:传入表达式字符串,返回计算结果
|
|
|
public static double evaluate(String expr) {
|
|
|
List<String> rpn = toRPN(expr);
|
|
|
return evalRPN(rpn);
|
|
|
}
|
|
|
|
|
|
}
|