返回
正则表达式与栈结合,优雅评估数学表达式
java
2024-03-06 06:43:08
巧用正则表达式和栈,优雅评估数学表达式
问题陈述
在编程中,我们经常需要处理数学表达式。能否通过提供字符串形式的表达式,优雅地计算结果呢?本文将探讨如何使用正则表达式和栈在 Java 中高效评估数学表达式。
解决方法
正则表达式提取操作数和运算符
正则表达式(Regex)是一种强大的字符串模式匹配工具。对于数学表达式,我们可以使用以下正则表达式提取操作数和运算符:
[-+]?[0-9]*\.?[0-9]+|[+\-*/()]
它匹配:
- 以正号或负号开头的数字
- 小数
- 加号、减号、乘号、除号或括号
栈存储操作数和运算符
栈是一种后进先出(LIFO)数据结构,这意味着最后添加的元素将首先被移除。我们将使用栈来存储操作数和运算符,并从后往前处理表达式。
算法步骤
- 使用正则表达式将表达式分成操作数和运算符的列表。
- 创建一个栈来存储操作数。
- 遍历操作数和运算符的列表:
- 如果遇到操作数,将其推入栈中。
- 如果遇到运算符,弹出栈顶的两个操作数,执行运算,并将结果推入栈中。
- 栈顶元素是表达式的值。
示例解析
以表达式 "10-4*5"
为例:
- 正则表达式将其分成:
["10", "-", "4", "*", "5"]
。 - 创建一个栈并推入
10
。 - 弹出栈顶的两个操作数
4
和5
,执行乘法4 * 5
并将结果20
推入栈中。 - 弹出栈顶的两个操作数
10
和20
,执行减法10 - 20
并将结果-10
推入栈中。 - 栈顶元素
-10
是表达式的值。
Java 实现
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Stack;
public class MathExpressionEvaluator {
private static final Pattern PATTERN = Pattern.compile("[-+]?[0-9]*\\.?[0-9]+|[+\\-*/()]");
public static double evaluate(String expression) {
Stack<Double> operands = new Stack<>();
Stack<Character> operators = new Stack<>();
Matcher matcher = PATTERN.matcher(expression);
while (matcher.find()) {
String token = matcher.group();
char ch = token.charAt(0);
if (Character.isDigit(ch)) {
operands.push(Double.parseDouble(token));
} else if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
operators.push(ch);
} else if (ch == '(') {
// Do nothing
} else if (ch == ')') {
double operand2 = operands.pop();
double operand1 = operands.pop();
char operator = operators.pop();
double result = calculate(operand1, operand2, operator);
operands.push(result);
}
}
return operands.pop();
}
private static double calculate(double operand1, double operand2, char operator) {
switch (operator) {
case '+':
return operand1 + operand2;
case '-':
return operand1 - operand2;
case '*':
return operand1 * operand2;
case '/':
return operand1 / operand2;
default:
throw new IllegalArgumentException("Invalid operator: " + operator);
}
}
}
结论
使用正则表达式和栈,我们可以轻松优雅地评估字符串形式的数学表达式,无需冗长的 if-else 语句。这种方法兼具简洁性、效率性和可扩展性。
常见问题解答
1. 这种方法是否支持负数?
是的,支持负数。正则表达式匹配以正号或负号开头的数字。
2. 如何处理小数?
正则表达式也匹配小数,使用 .
表示小数点。
3. 如何处理括号?
括号用作运算优先级的指示符。当遇到右括号时,我们将弹出栈顶的两个操作数和一个运算符,执行运算并将其结果推入栈中。
4. 是否可以扩展此算法来处理更复杂的表达式?
是的,通过修改正则表达式和计算方法,可以扩展算法来处理函数、三角函数等更复杂的运算。
5. 如何处理除数为零的情况?
为了处理除数为零的情况,可以在 calculate
方法中添加一个检查,如果除数为零,则抛出异常。