将字符串计算为双精度后缀符号

问题描述

我想创建一个方法,以后缀表示法解释这个列表(方法“words”将一个字符串拆分成一个单词列表,用\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,Double>> sub = x -> y -> x - y;
    private static final Function<Double,Double>> mul = x -> y -> x * y;
    private static final Function<Double,Double>> div = x -> y -> x / y;
    private static final 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. 我用 if-else 替换了 switch-case 语句(我不必使用 break,因为我 return .
  2. 我删除了不必要的 else 语句(如果您已经在 if 语句中返回,请不要使用它们)。
  3. 我提取了一个名为“evalSingle”的方法(您必须将 ??? 替换为 addsub ... are)。

代码

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,sub);
            case "*":
                return evalSingle(s,mul);
            case "/":
                return evalSingle(s,div);
            case "^":
                return evalSingle(s,pow);
            case "!":
                return evalSingle(s,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)。

只是解释一下,这是一个移位归约解析器的最小实现,当您有一个数字时,只需将其推入堆栈(移位),当运算符将最顶层的操作数替换为操作结果时。

>

请注意,我不是在这里检查错误,因此不正确的表达式可能会返回错误的值。

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();
    }