简体   繁体   English

如何让我的评估字符串方程的代码与 PI 和 E 一起使用

[英]How do I allow my code that evaluates string equations to work with PI and E

I took this code from a previously answered question and I am trying to expand it so that it works with E and PI when the String contains "E" and "PI".我从之前回答的问题中获取了这段代码,我正在尝试扩展它,以便当字符串包含“E”和“PI”时它可以与 E 和 PI 一起使用。 I don't really understand how the code works because I am pretty new to Java and the explanation on the original comment was not great (I have since lost the link to the comment unfortunately).我真的不明白代码是如何工作的,因为我对 Java 很陌生,并且对原始评论的解释不是很好(不幸的是,我已经失去了评论的链接)。

public static double eval(final String str) {
    return new Object() {
        int pos = -1, ch;
        void nextChar() {
            ch = (++pos < str.length()) ? str.charAt(pos) : -1;
        }

        boolean eat(int charToEat) {
            while (ch == ' ') nextChar();
            if (ch == charToEat) {
                nextChar();
                return true;
            }
            return false;
        }

        double parse() {
            nextChar();
            double x = parseExpression();
            if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch);
            return x;
        }

        // Grammar:
        // expression = term | expression `+` term | expression `-` term
        // term = factor | term `*` factor | term `/` factor
        // factor = `+` factor | `-` factor | `(` expression `)`
        //        | number | functionName factor | factor `^` factor

        double parseExpression() {
            double x = parseTerm();
            for (;;) {
                if      (eat('+')) x += parseTerm(); // addition
                else if (eat('-')) x -= parseTerm(); // subtraction
                else return x;
            }
        }

        double parseTerm() {
            double x = parseFactor();
            for (;;) {
                if      (eat('*')) x *= parseFactor(); // multiplication
                else if (eat('/')) x /= parseFactor(); // division
                else return x;
            }
        }

        double parseFactor() {
            if (eat('+')) return parseFactor(); // unary plus
            if (eat('-')) return -parseFactor(); // unary minus

            double x;
            int startPos = this.pos;
            if (eat('(')) { // parentheses
                x = parseExpression();
                eat(')');
            } else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
                while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
                x = Double.parseDouble(str.substring(startPos, this.pos));
            } else if (ch >= 'a' && ch <= 'z') { // functions
                while (ch >= 'a' && ch <= 'z') nextChar();
                String func = str.substring(startPos, this.pos);
                x = parseFactor();
                if (func.equals("sqrt")) x = Math.sqrt(x);
                else if (func.equals("sin")) x = Math.sin(Math.toRadians(x));
                else if (func.equals("cos")) x = Math.cos(Math.toRadians(x));
                else if (func.equals("tan")) x = Math.tan(Math.toRadians(x));
                else if (func.equals("csc")) x = 1/Math.sin(Math.toRadians(x));
                else if (func.equals("sec")) x = 1/Math.cos(Math.toRadians(x));
                else if (func.equals("cot")) x = 1/Math.tan(Math.toRadians(x));
                else if (func.equals("log")) x = Math.log(x);
                else throw new RuntimeException("Unknown function: " + func);
            } else {
                throw new RuntimeException("Unexpected: " + (char)ch);
            }

            if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation

            return x;
        }
    }.parse();
}

The key to the solution is to modify the grammar to support your supported named constants.解决方案的关键是修改语法以支持您支持的命名常量。 It is therefore a requirement (as your examples suggest) that named constants be in capital letters: A - Z (to distinguish between functions).因此,要求(如您的示例所示)命名常量必须大写: A - Z (以区分函数)。

(The specified grammar is incomplete in that it does not specify the syntax of functions but the code suggests it is lower-case characters in a subset of trig and log functions.) (指定的语法是不完整的,因为它没有指定函数的语法,但代码表明它是 trig 和 log 函数子集中的小写字符。)

So, grammar is updated as:因此,语法更新为:

// Grammar:
// expression = term | expression `+` term | expression `-` term
// term = factor | term `*` factor | term `/` factor
// factor = `+` factor | `-` factor | `(` expression `)`
//        | number | functionName factor | factor `^` factor | namedConstant
// namedConstant = 'PI' | 'E'

And the only modification required is to update parseFactor and the only change to it is to add the else if at the bottom.唯一需要修改的是更新parseFactor ,唯一的改变是在底部添加else if

double parseFactor() {
    if (eat('+')) return parseFactor(); // unary plus
    if (eat('-')) return -parseFactor(); // unary minus

    double x;
    int startPos = this.pos;
    if (eat('(')) { // parentheses
        //..no changes
    } else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
        //..no changes
    } else if (ch >= 'a' && ch <= 'z') { // functions
        //..no changes

    } else if (ch >= 'A' && ch <= 'Z') { // named constants
        while (ch >= 'A' && ch <= 'Z') nextChar();
        String s = str.substring(startPos,this.pos);
        if (s.equals("PI")) {
            x = Math.PI;
        } else if (s.equals("E")) {
            x = Math.E;
        } else {
            throw new RuntimeException("Invalid constant: "+s);
        }
    } else {
        throw new RuntimeException("Unexpected: " + (char)ch);
    }

    //...continue with your code

So these tests:所以这些测试:

    double d = eval("2.5");
    System.out.println(d);

    d = eval("-2.5");
    System.out.println(d);
    
    d = eval("2.5 * 10");
    System.out.println(d);
    
    d = eval("3 * PI");
    System.out.println(d);
    
    d = eval("E ^ 2");
    System.out.println(d);

    d = eval("7.5 + (2.5 * PI)");
    System.out.println(d);

    d = eval("sqrt PI");
    System.out.println(d);

    try {
        d = eval("K / 3");
    System.out.println(d);
    } catch (RuntimeException re) {
        System.out.println("--E--");
    }

Produces:产生:

2.5
-2.5
25.0
9.42477796076938
7.3890560989306495
15.353981633974483
1.7724538509055159
--E--

Postscript:后记:

Some of your operations (terms and functions) do not protect against invalid input, such as divide-by-zero and undefined functions such as log 0 .您的某些操作(术语和函数)不能防止无效输入,例如divide-by-zero和未定义的函数,例如log 0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM