返回

正则表达式与栈结合,优雅评估数学表达式

java

巧用正则表达式和栈,优雅评估数学表达式

问题陈述

在编程中,我们经常需要处理数学表达式。能否通过提供字符串形式的表达式,优雅地计算结果呢?本文将探讨如何使用正则表达式和栈在 Java 中高效评估数学表达式。

解决方法

正则表达式提取操作数和运算符

正则表达式(Regex)是一种强大的字符串模式匹配工具。对于数学表达式,我们可以使用以下正则表达式提取操作数和运算符:

[-+]?[0-9]*\.?[0-9]+|[+\-*/()]

它匹配:

  • 以正号或负号开头的数字
  • 小数
  • 加号、减号、乘号、除号或括号

栈存储操作数和运算符

栈是一种后进先出(LIFO)数据结构,这意味着最后添加的元素将首先被移除。我们将使用栈来存储操作数和运算符,并从后往前处理表达式。

算法步骤

  1. 使用正则表达式将表达式分成操作数和运算符的列表。
  2. 创建一个栈来存储操作数。
  3. 遍历操作数和运算符的列表:
    • 如果遇到操作数,将其推入栈中。
    • 如果遇到运算符,弹出栈顶的两个操作数,执行运算,并将结果推入栈中。
  4. 栈顶元素是表达式的值。

示例解析

以表达式 "10-4*5" 为例:

  1. 正则表达式将其分成:["10", "-", "4", "*", "5"]
  2. 创建一个栈并推入 10
  3. 弹出栈顶的两个操作数 45,执行乘法 4 * 5 并将结果 20 推入栈中。
  4. 弹出栈顶的两个操作数 1020,执行减法 10 - 20 并将结果 -10 推入栈中。
  5. 栈顶元素 -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 方法中添加一个检查,如果除数为零,则抛出异常。