You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Demo1/src/ExpressionEvaluator.java

325 lines
9.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import java.util.*;
/**
* 数学表达式计算器
* 支持基本四则运算、括号、平方、开根号和三角函数
*/
public class ExpressionEvaluator {
/**
* 计算数学表达式的值
*/
public static double evaluate(String expression) {
try {
// 预处理表达式:处理特殊符号
expression = preprocessExpression(expression);
// 使用栈和递归下降解析器计算
return parseExpression(expression);
} catch (Exception e) {
System.err.println("计算表达式失败: " + expression + " - " + e.getMessage());
e.printStackTrace();
return 0;
}
}
/**
* 预处理表达式:将特殊符号转换为可计算的形式
*/
private static String preprocessExpression(String expr) {
// 移除所有空格
expr = expr.replaceAll("\\s+", "");
// 处理三角函数sin(30°) -> 计算实际值
expr = replaceTrigFunctions(expr);
// 处理平方符号5² -> (5*5)
expr = replaceSquares(expr);
// 处理开根号√25 -> 5
expr = replaceSqrts(expr);
return 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);
StringBuffer sb = new StringBuffer();
while (m.find()) {
int degrees = Integer.parseInt(m.group(1));
double radians = Math.toRadians(degrees);
double result = 0;
switch (funcName) {
case "sin":
result = Math.sin(radians);
break;
case "cos":
result = Math.cos(radians);
break;
case "tan":
result = Math.tan(radians);
break;
}
// 替换为括号包裹的数值
m.appendReplacement(sb, "(" + result + ")");
}
m.appendTail(sb);
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);
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 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 (pos[0] < expr.length() && expr.charAt(pos[0]) == '(') {
pos[0]++; // 跳过 '('
double result = parseAddSubtract(expr, pos);
pos[0]++; // 跳过 ')'
return result;
}
// 处理负号
boolean negative = false;
if (pos[0] < expr.length() && expr.charAt(pos[0]) == '-') {
negative = true;
pos[0]++;
}
// 解析数字
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;
}
/**
* 生成错误答案选项
*/
public static String[] generateWrongAnswers(double correctAnswer, int count) {
Set<String> wrongAnswers = new HashSet<>();
Random random = new Random();
while (wrongAnswers.size() < count) {
double wrongValue;
// 生成不同类型的错误答案
int type = random.nextInt(4);
switch (type) {
case 0: // 加减一个随机数
wrongValue = correctAnswer + (random.nextInt(20) - 10);
break;
case 1: // 乘以一个小数
wrongValue = correctAnswer * (0.5 + random.nextDouble());
break;
case 2: // 除以一个数
wrongValue = correctAnswer / (1.5 + random.nextDouble() * 2);
break;
default: // 完全随机
wrongValue = random.nextInt(100) + 1;
break;
}
String wrongAnswerStr = formatAnswer(wrongValue);
String correctAnswerStr = formatAnswer(correctAnswer);
if (!wrongAnswerStr.equals(correctAnswerStr)) {
wrongAnswers.add(wrongAnswerStr);
}
}
return wrongAnswers.toArray(new String[0]);
}
/**
* 格式化答案显示
*/
public static String formatAnswer(double answer) {
if (Math.abs(answer - Math.round(answer)) < 0.001) {
return String.valueOf(Math.round(answer));
} else {
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;
}
}
}