[英]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.