Java 将字符串求值为双精度(后缀表示法)

Java 将字符串求值为双精度(后缀表示法),java,postfix-notation,Java,Postfix Notation,我想创建一个方法,用后缀符号解释这个列表(方法“words”将一个字符串拆分为一个单词列表,用\s分隔)。这就是我得到的,我想知道是否有一个较短的方法来解决这个问题,因为我经常在那里重复我自己 public static double eval(String expr) { return eval_(new ListStack<Double>() , words(expr)); } private static double eval_(St

我想创建一个方法,用后缀符号解释这个列表(方法“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());
        }
    }

它总是抛出一个“NumberFormatException”。(可能是因为它无法将“+”解析为双精度)

我做了什么

  • 我将
    if
    -
    else
    语句替换为
    开关
    -
    大小写
    (我不必使用
    中断
    ,因为我
    返回
  • 我删除了不必要的
    else
    -语句(如果已在
    if
    -语句中返回,请不要使用它们)
  • 我提取了一个名为“evalSingle”的方法(您必须用
    add
    sub
    …替换???)
  • 代码

    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());
    }
    
    private static double eval(堆栈,列表expr){
    if(expr.isEmpty()){
    返回s.top();
    }如果(!expr.isEmpty()){
    开关(expr.head()){
    格“+”:
    返回evalSingle(s、expr、add);
    案例“-”:
    返回evalSingle(s、expr、sub);
    案例“*”:
    返回评估单(s、expr、mul);
    案例“/:
    返回evalSingle(s、expr、div);
    案例“^”:
    返回evalSingle(s、expr、pow);
    案例“!”:
    返回evalSingle(s、expr、fact);
    }
    }
    Double value=Double.parseDouble(expr.head());
    s=s.push(值);
    返回eval_uS(expr.tail());
    }
    专用静态双evalSingle(堆栈、列表表达式、运算符){
    双fstValue=s.top();
    s=s.pop();
    双SND值=s.top();
    s=s.pop();
    s=s.push(operator==fact?operator.apply(fstValue):operator.apply(fstValue).apply(sndValue));
    返回eval_uS(expr.tail());
    }
    
    我认为你的教授是在开玩笑,但是是的,你把它缩短了(不是一行,除非你删除了所有LF)

    只是解释一下,这是一个移位减少解析器的最小实现,当您有一个数字时,只需将其推送到堆栈(shift),当运算符用运算结果替换最上面的操作数时

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

    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();
        }
        
    
    import java.util.Stack;
    公共类后固定语法分析器{
    公共静态双值(字符串表达式){
    堆栈s=新堆栈();
    用于(字符串标记:expr.split(\\s+)){
    交换机(令牌){
    格“+”:
    s、 推(s.pop()+s.pop());
    打破
    案例“-”:
    s、 推(s.pop()-s.pop());
    打破
    案例“*”:
    s、 推(s.pop()*s.pop());
    打破
    案例“/:
    s、 推(s.pop()/s.pop());
    打破
    案例“^”:
    {
    double exp=s.pop();
    s、 push(Math.pow(s.pop(),exp));
    }
    打破
    案例“!”:
    //在这里定义阶乘函数s.push(fact(s.pop());
    打破
    违约:
    s、 推送(Double.valueOf(token));
    }
    }
    返回s.pop();
    }
    
    提供所需输入和输出的示例将非常有用。我发布了一个可能的解决方案,但您应该澄清您正在使用的一些方法(sum、add、mul、div、pow),这些方法是否已作为库或实现的一部分提供?请提供说明和签名。其他点“fact”应该有一个操作数,但您从堆栈中弹出两个值。我添加了一些函数,以便您可以看到它们的作用。感谢您帮我解决此问题!如果堆栈的行为不符合t如果是标准Java堆栈,那么您应该用一些相应的代码替换pop(),实现中的popTop()是什么?此外,如果您得到NumberFormatException,那么您的令牌既不是数字,也不是任何已定义的运算符,因此肯定是错误的输入。s.pop()返回堆栈,而不是单个变量(我们必须自己实现堆栈(和列表)。因此,我可能会在那里遇到问题。@Sentenza_IV所以我询问了自定义函数,因为这里我使用了Java标准堆栈实现,其中pop()返回一个元素。
        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;
        }
    
    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());
    }
    
    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();
        }