|
|
|
|
@ -11,119 +11,211 @@ public class ExpressionEvaluator {
|
|
|
|
|
*/
|
|
|
|
|
public static double evaluate(String expression) {
|
|
|
|
|
try {
|
|
|
|
|
// 预处理表达式
|
|
|
|
|
// 预处理表达式:处理特殊符号
|
|
|
|
|
expression = preprocessExpression(expression);
|
|
|
|
|
|
|
|
|
|
// 使用递归下降解析器计算
|
|
|
|
|
return evaluateExpression(expression);
|
|
|
|
|
// 使用栈和递归下降解析器计算
|
|
|
|
|
return parseExpression(expression);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// 如果计算失败,返回一个随机值作为示例
|
|
|
|
|
return new Random().nextInt(100) + 1;
|
|
|
|
|
System.err.println("计算表达式失败: " + expression + " - " + e.getMessage());
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 预处理表达式
|
|
|
|
|
* 预处理表达式:将特殊符号转换为可计算的形式
|
|
|
|
|
*/
|
|
|
|
|
private static String preprocessExpression(String expr) {
|
|
|
|
|
// 移除空格
|
|
|
|
|
// 移除所有空格
|
|
|
|
|
expr = expr.replaceAll("\\s+", "");
|
|
|
|
|
|
|
|
|
|
// 处理平方符号
|
|
|
|
|
expr = expr.replaceAll("(\\d+)²", "pow($1,2)");
|
|
|
|
|
// 处理三角函数:sin(30°) -> 计算实际值
|
|
|
|
|
expr = replaceTrigFunctions(expr);
|
|
|
|
|
|
|
|
|
|
// 处理开根号
|
|
|
|
|
expr = expr.replaceAll("√(\\d+)", "sqrt($1)");
|
|
|
|
|
// 处理平方符号:5² -> (5*5)
|
|
|
|
|
expr = replaceSquares(expr);
|
|
|
|
|
|
|
|
|
|
// 处理三角函数(转换为弧度)
|
|
|
|
|
expr = expr.replaceAll("sin\\((\\d+)°\\)", "sin(Math.toRadians($1))");
|
|
|
|
|
expr = expr.replaceAll("cos\\((\\d+)°\\)", "cos(Math.toRadians($1))");
|
|
|
|
|
expr = expr.replaceAll("tan\\((\\d+)°\\)", "tan(Math.toRadians($1))");
|
|
|
|
|
// 处理开根号:√25 -> 5
|
|
|
|
|
expr = replaceSqrts(expr);
|
|
|
|
|
|
|
|
|
|
return expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 简化的表达式计算
|
|
|
|
|
* 替换三角函数为实际计算值
|
|
|
|
|
*/
|
|
|
|
|
private static double evaluateExpression(String expr) {
|
|
|
|
|
// 处理简单的数学运算
|
|
|
|
|
if (expr.matches("\\d+")) {
|
|
|
|
|
return Double.parseDouble(expr);
|
|
|
|
|
}
|
|
|
|
|
private static String replaceTrigFunctions(String expr) {
|
|
|
|
|
// 处理 sin(角度°)
|
|
|
|
|
expr = replaceFunction(expr, "sin");
|
|
|
|
|
// 处理 cos(角度°)
|
|
|
|
|
expr = replaceFunction(expr, "cos");
|
|
|
|
|
// 处理 tan(角度°)
|
|
|
|
|
expr = replaceFunction(expr, "tan");
|
|
|
|
|
|
|
|
|
|
return expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 替换单个三角函数
|
|
|
|
|
*/
|
|
|
|
|
private static String replaceFunction(String expr, String funcName) {
|
|
|
|
|
String pattern = funcName + "\\((\\d+)°\\)";
|
|
|
|
|
java.util.regex.Pattern p = java.util.regex.Pattern.compile(pattern);
|
|
|
|
|
java.util.regex.Matcher m = p.matcher(expr);
|
|
|
|
|
|
|
|
|
|
// 处理加法
|
|
|
|
|
if (expr.contains("+")) {
|
|
|
|
|
String[] parts = expr.split("\\+");
|
|
|
|
|
StringBuffer sb = new StringBuffer();
|
|
|
|
|
while (m.find()) {
|
|
|
|
|
int degrees = Integer.parseInt(m.group(1));
|
|
|
|
|
double radians = Math.toRadians(degrees);
|
|
|
|
|
double result = 0;
|
|
|
|
|
for (String part : parts) {
|
|
|
|
|
result += evaluateExpression(part.trim());
|
|
|
|
|
|
|
|
|
|
switch (funcName) {
|
|
|
|
|
case "sin":
|
|
|
|
|
result = Math.sin(radians);
|
|
|
|
|
break;
|
|
|
|
|
case "cos":
|
|
|
|
|
result = Math.cos(radians);
|
|
|
|
|
break;
|
|
|
|
|
case "tan":
|
|
|
|
|
result = Math.tan(radians);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
// 替换为括号包裹的数值
|
|
|
|
|
m.appendReplacement(sb, "(" + result + ")");
|
|
|
|
|
}
|
|
|
|
|
m.appendTail(sb);
|
|
|
|
|
|
|
|
|
|
// 处理减法
|
|
|
|
|
if (expr.contains("-") && !expr.startsWith("-")) {
|
|
|
|
|
int lastMinus = expr.lastIndexOf("-");
|
|
|
|
|
String left = expr.substring(0, lastMinus);
|
|
|
|
|
String right = expr.substring(lastMinus + 1);
|
|
|
|
|
return evaluateExpression(left) - evaluateExpression(right);
|
|
|
|
|
return sb.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 替换平方符号
|
|
|
|
|
*/
|
|
|
|
|
private static String replaceSquares(String expr) {
|
|
|
|
|
java.util.regex.Pattern p = java.util.regex.Pattern.compile("(\\d+)²");
|
|
|
|
|
java.util.regex.Matcher m = p.matcher(expr);
|
|
|
|
|
|
|
|
|
|
StringBuffer sb = new StringBuffer();
|
|
|
|
|
while (m.find()) {
|
|
|
|
|
int num = Integer.parseInt(m.group(1));
|
|
|
|
|
int result = num * num;
|
|
|
|
|
m.appendReplacement(sb, String.valueOf(result));
|
|
|
|
|
}
|
|
|
|
|
m.appendTail(sb);
|
|
|
|
|
|
|
|
|
|
// 处理乘法
|
|
|
|
|
if (expr.contains("*")) {
|
|
|
|
|
String[] parts = expr.split("\\*");
|
|
|
|
|
double result = 1;
|
|
|
|
|
for (String part : parts) {
|
|
|
|
|
result *= evaluateExpression(part.trim());
|
|
|
|
|
return sb.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 替换开根号
|
|
|
|
|
*/
|
|
|
|
|
private static String replaceSqrts(String expr) {
|
|
|
|
|
java.util.regex.Pattern p = java.util.regex.Pattern.compile("√(\\d+)");
|
|
|
|
|
java.util.regex.Matcher m = p.matcher(expr);
|
|
|
|
|
|
|
|
|
|
StringBuffer sb = new StringBuffer();
|
|
|
|
|
while (m.find()) {
|
|
|
|
|
int num = Integer.parseInt(m.group(1));
|
|
|
|
|
double result = Math.sqrt(num);
|
|
|
|
|
m.appendReplacement(sb, String.valueOf(result));
|
|
|
|
|
}
|
|
|
|
|
m.appendTail(sb);
|
|
|
|
|
|
|
|
|
|
return sb.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解析并计算表达式(支持运算符优先级)
|
|
|
|
|
*/
|
|
|
|
|
private static double parseExpression(String expr) {
|
|
|
|
|
return parseAddSubtract(expr, new int[]{0});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解析加减法(最低优先级)
|
|
|
|
|
*/
|
|
|
|
|
private static double parseAddSubtract(String expr, int[] pos) {
|
|
|
|
|
double left = parseMultiplyDivide(expr, pos);
|
|
|
|
|
|
|
|
|
|
while (pos[0] < expr.length()) {
|
|
|
|
|
char op = expr.charAt(pos[0]);
|
|
|
|
|
if (op == '+' || op == '-') {
|
|
|
|
|
pos[0]++;
|
|
|
|
|
double right = parseMultiplyDivide(expr, pos);
|
|
|
|
|
if (op == '+') {
|
|
|
|
|
left += right;
|
|
|
|
|
} else {
|
|
|
|
|
left -= right;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理除法
|
|
|
|
|
if (expr.contains("/")) {
|
|
|
|
|
int lastDiv = expr.lastIndexOf("/");
|
|
|
|
|
String left = expr.substring(0, lastDiv);
|
|
|
|
|
String right = expr.substring(lastDiv + 1);
|
|
|
|
|
double rightValue = evaluateExpression(right);
|
|
|
|
|
if (rightValue != 0) {
|
|
|
|
|
return evaluateExpression(left) / rightValue;
|
|
|
|
|
return left;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解析乘除法(中等优先级)
|
|
|
|
|
*/
|
|
|
|
|
private static double parseMultiplyDivide(String expr, int[] pos) {
|
|
|
|
|
double left = parseFactor(expr, pos);
|
|
|
|
|
|
|
|
|
|
while (pos[0] < expr.length()) {
|
|
|
|
|
char op = expr.charAt(pos[0]);
|
|
|
|
|
if (op == '*' || op == '/') {
|
|
|
|
|
pos[0]++;
|
|
|
|
|
double right = parseFactor(expr, pos);
|
|
|
|
|
if (op == '*') {
|
|
|
|
|
left *= right;
|
|
|
|
|
} else {
|
|
|
|
|
if (right != 0) {
|
|
|
|
|
left /= right;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return left;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解析因子(数字或括号表达式)
|
|
|
|
|
*/
|
|
|
|
|
private static double parseFactor(String expr, int[] pos) {
|
|
|
|
|
// 跳过空格
|
|
|
|
|
while (pos[0] < expr.length() && expr.charAt(pos[0]) == ' ') {
|
|
|
|
|
pos[0]++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理括号
|
|
|
|
|
if (expr.contains("(")) {
|
|
|
|
|
int start = expr.lastIndexOf("(");
|
|
|
|
|
int end = expr.indexOf(")", start);
|
|
|
|
|
String inner = expr.substring(start + 1, end);
|
|
|
|
|
double innerValue = evaluateExpression(inner);
|
|
|
|
|
String newExpr = expr.substring(0, start) + innerValue + expr.substring(end + 1);
|
|
|
|
|
return evaluateExpression(newExpr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理特殊函数
|
|
|
|
|
if (expr.startsWith("pow(")) {
|
|
|
|
|
// 简化处理:假设是 pow(x,2) 的形式
|
|
|
|
|
String inner = expr.substring(4, expr.length() - 1);
|
|
|
|
|
String[] parts = inner.split(",");
|
|
|
|
|
if (parts.length == 2) {
|
|
|
|
|
double base = Double.parseDouble(parts[0]);
|
|
|
|
|
double exp = Double.parseDouble(parts[1]);
|
|
|
|
|
return Math.pow(base, exp);
|
|
|
|
|
}
|
|
|
|
|
if (pos[0] < expr.length() && expr.charAt(pos[0]) == '(') {
|
|
|
|
|
pos[0]++; // 跳过 '('
|
|
|
|
|
double result = parseAddSubtract(expr, pos);
|
|
|
|
|
pos[0]++; // 跳过 ')'
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (expr.startsWith("sqrt(")) {
|
|
|
|
|
String inner = expr.substring(5, expr.length() - 1);
|
|
|
|
|
return Math.sqrt(Double.parseDouble(inner));
|
|
|
|
|
// 处理负号
|
|
|
|
|
boolean negative = false;
|
|
|
|
|
if (pos[0] < expr.length() && expr.charAt(pos[0]) == '-') {
|
|
|
|
|
negative = true;
|
|
|
|
|
pos[0]++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 默认返回解析的数字
|
|
|
|
|
try {
|
|
|
|
|
return Double.parseDouble(expr);
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
return new Random().nextInt(50) + 1;
|
|
|
|
|
// 解析数字
|
|
|
|
|
int start = pos[0];
|
|
|
|
|
while (pos[0] < expr.length() &&
|
|
|
|
|
(Character.isDigit(expr.charAt(pos[0])) || expr.charAt(pos[0]) == '.')) {
|
|
|
|
|
pos[0]++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double value = Double.parseDouble(expr.substring(start, pos[0]));
|
|
|
|
|
return negative ? -value : value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -174,4 +266,59 @@ public class ExpressionEvaluator {
|
|
|
|
|
return String.format("%.2f", answer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 验证表达式语法是否正确
|
|
|
|
|
*/
|
|
|
|
|
public static boolean isValidMathExpression(String expression) {
|
|
|
|
|
// 基本语法检查
|
|
|
|
|
if (expression == null || expression.trim().isEmpty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查括号匹配
|
|
|
|
|
int balance = 0;
|
|
|
|
|
for (char c : expression.toCharArray()) {
|
|
|
|
|
if (c == '(') balance++;
|
|
|
|
|
if (c == ')') balance--;
|
|
|
|
|
if (balance < 0) return false;
|
|
|
|
|
}
|
|
|
|
|
if (balance != 0) return false;
|
|
|
|
|
|
|
|
|
|
// 检查运算符位置
|
|
|
|
|
String[] tokens = expression.split("\\s+");
|
|
|
|
|
for (int i = 0; i < tokens.length; i++) {
|
|
|
|
|
String token = tokens[i];
|
|
|
|
|
|
|
|
|
|
// 检查连续的运算符
|
|
|
|
|
if (isOperator(token) && i > 0 && isOperator(tokens[i-1])) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查数字后面直接跟左括号
|
|
|
|
|
if (i > 0 && isNumber(token) && i < tokens.length - 1 && "(".equals(tokens[i+1])) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查右括号后面直接跟数字
|
|
|
|
|
if (i > 0 && ")".equals(token) && i < tokens.length - 1 && isNumber(tokens[i+1])) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static boolean isOperator(String token) {
|
|
|
|
|
return "+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static boolean isNumber(String str) {
|
|
|
|
|
try {
|
|
|
|
|
Double.parseDouble(str);
|
|
|
|
|
return true;
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|