将字符串计算为 Double(后缀表示法)

Evaluate String to Double (Postfix-notation)

我想创建一个方法,以后缀表示法解释此列表(方法“单词”将字符串拆分为单词列表,单词列表由 \s 分隔。)。这就是我得到的,我想知道是否有更短的方法来解决这个问题,因为我经常在那里重复自己。

    public static double eval(String expr) {
        return eval_(new ListStack<Double>() , words(expr));
    }

    private static double eval_(Stack<Double> s, List<String> expr) {
        if (expr.isEmpty()) {
            return s.top();
        } else if (expr.head().equals("+")) {
            Double fstValue = s.top();
            s = s.pop();
            Double sndValue = s.top();
            s = s.pop();
            s = s.push(add.apply(fstValue).apply(sndValue));
            return eval_(s, expr.tail());
        } else if (expr.head().equals("-")) {
            Double fstValue = s.top();
            s = s.pop();
            Double sndValue = s.top();
            s = s.pop();
            s = s.push(sub.apply(fstValue).apply(sndValue));
            return eval_(s, expr.tail());
        } else if (expr.head().equals("*")) {
            Double fstValue = s.top();
            s = s.pop();
            Double sndValue = s.top();
            s = s.pop();
            s = s.push(mul.apply(fstValue).apply(sndValue));
            return eval_(s, expr.tail());
        } else if (expr.head().equals("/")) {
            Double fstValue = s.top();
            s = s.pop();
            Double sndValue = s.top();
            s = s.pop();
            s = s.push(div.apply(fstValue).apply(sndValue));
            return eval_(s, expr.tail());
        } else if (expr.head().equals("^")) {
            Double fstValue = s.top();
            s = s.pop();
            Double sndValue = s.top();
            s = s.pop();
            s = s.push(pow.apply(fstValue).apply(sndValue));
            return eval_(s, expr.tail());
        } else if (expr.head().equals("!")) {
            Double fstValue = s.top();
            s = s.pop();
            s = s.push(fact.apply(fstValue));
            return eval_(s, expr.tail());
        } else {
            Double value = Double.parseDouble(expr.head());
            s = s.push(value);
            return eval_(s, expr.tail());
        }
    }

我试着把它缩短一点:

    private static double eval_(Stack<Double> s, List<String> expr) {
        Double fstValue;
        Double sndValue;
        if (expr.isEmpty()) {
            return s.top();
        } else if (!expr.isEmpty()) {
            fstValue = s.top();
            s = s.pop();
            sndValue = s.top();
            s = s.pop();
            if (expr.head().equals("+") && !expr.isEmpty()) {
                s = s.push(add.apply(fstValue).apply(sndValue));
                return eval_(s, expr.tail());
            } else if (expr.head().equals("-") && !expr.isEmpty()) {
                s = s.push(sub.apply(fstValue).apply(sndValue));
                return eval_(s, expr.tail());
            } else if (expr.head().equals("*") && !expr.isEmpty()) {
                s = s.push(mul.apply(fstValue).apply(sndValue));
                return eval_(s, expr.tail());
            } else if (expr.head().equals("/") && !expr.isEmpty()) {
                s = s.push(div.apply(fstValue).apply(sndValue));
                return eval_(s, expr.tail());
            } else if (expr.head().equals("^") && !expr.isEmpty()) {
                s = s.push(pow.apply(fstValue).apply(sndValue));
                return eval_(s, expr.tail());
            } else if (expr.head().equals("!") && !expr.isEmpty()) {
                s = s.push(fact.apply(fstValue));
                return eval_(s, expr.tail());
            }
            else {
                Double value = Double.parseDouble(expr.head());
                s = s.push(value);
                return eval_(s, expr.tail());
            }
        } else {
            Double value = Double.parseDouble(expr.head());
            s = s.push(value);
            return eval_(s, expr.tail());
        }
    }
Edit:
Input:
System.out.println(eval(5 6 + 8 *));
'Interpreted as (5+6) * 8 = 11 * 8'
Output: "88"
    private static final Function<Double, Function<Double, Double>> add  = x -> y -> x + y;
    private static final Function<Double, Function<Double, Double>> sub = x -> y -> x - y;
    private static final Function<Double, Function<Double, Double>> mul = x -> y -> x * y;
    private static final Function<Double, Function<Double, Double>> div = x -> y -> x / y;
    private static final Function<Double, Function<Double, Double>> pow = x -> y -> Math.pow(x,y);
    private static final Function<Double, Double> fact = Postfix::fact;


    public static double fact(double i){
        return i > 1 ? i * fact(i - 1) : 1;
    }

它既不工作也不短。 (我的教授告诉我我可以一行完成)。 感谢您帮助我!

编辑 2:我尝试了@Rocco 的回答(并使用 IntelliJ 简化了它)

    private static double eval(String expr) {
        switch (expr) {
            case "+" -> s.push(add.apply(s.popTop().fst).apply(s.popTop().fst));
            case "-" -> s.push(sub.apply(s.popTop().fst).apply(s.popTop().fst));
            case "*" -> s.push(mul.apply(s.popTop().fst).apply(s.popTop().fst));
            case "/" -> s.push(div.apply(s.popTop().fst).apply(s.popTop().fst));
            case "^" -> {
                double exp = s.popTop().fst;
                s.push(Math.pow(s.popTop().fst, exp));
            }
            case "!" -> {
                s.push(fact.apply(s.popTop().fst));
            }
            default -> s.push(Double.valueOf(String.valueOf(expr)));
        }
        return s.popTop().fst;
    }

它总是抛出“NumberFormatException”。 (可能是因为它无法将“+”解析为 Double)

我做了什么

  1. 我用 switch-case 替换了 if-else 语句(我不必使用 break,因为我 return.
  2. 我删除了不必要的 else-语句(如果您已经在 if-语句中返回,请不要使用它们)。
  3. 我提取了一个名为“evalSingle”的方法(您必须将 ??? 替换为 addsub ... 中的任何内容)。

代码

private static double eval_(Stack <Double> s, List <String> expr) {
    if (expr.isEmpty()) {
        return s.top();
    } else if (!expr.isEmpty()) {
        switch (expr.head()) {
            case "+":
                return evalSingle(s, expr, add);
            case "-":
                return evalSingle(s, expr, sub);
            case "*":
                return evalSingle(s, expr, mul);
            case "/":
                return evalSingle(s, expr, div);
            case "^":
                return evalSingle(s, expr, pow);
            case "!":
                return evalSingle(s, expr, fact);
        }
    }
    Double value = Double.parseDouble(expr.head());
    s = s.push(value);
    return eval_(s, expr.tail());
}

private static double evalSingle(Stack <Double> s, List <String> expr, ??? operator) {
    Double fstValue = s.top();
    s = s.pop();
    Double sndValue = s.top();
    s = s.pop();

    s = s.push(operator == fact ? operator.apply(fstValue) : operator.apply(fstValue).apply(sndValue));
    return eval_(s, expr.tail());
}

我认为你的教授在开玩笑,但是,是的,你把它变短了(不是一行,除非你删除所有的 LF)。

只是为了解释一下,这是 shift-reduce 解析器的最小实现,当你有一个数字时,只需将它推入堆栈(shift),当运算符用操作结果替换最顶层的操作数时。

请注意,我不会在此处检查错误,因此不正确的表达式可能会 return 产生错误的值。

import java.util.Stack;

public class PostFixEprParser {
    public static double eval(String expr) {
        Stack<Double> s=new Stack<>();
        for (String token: expr.split("\s+")) {
            switch (token) {
            case "+":
                s.push(s.pop()+s.pop());
                break;
            case "-":
                s.push(s.pop()-s.pop());
                break;
            case "*":
                s.push(s.pop()*s.pop());
                break;
            case "/":
                s.push(s.pop()/s.pop());
                break;
            case "^":
            {
                double exp=s.pop();
                s.push(Math.pow(s.pop(), exp));
            }
                break;
            case "!":
                //TODO Here define your factorial function s.push(fact(s.pop()));
                break;
            default:
                s.push(Double.valueOf(token));
            }
        }
        return s.pop();
    }