Tôi đang cố gắng viết một thói quen Java để đánh giá các biểu thức toán học đơn giản từ String
các giá trị như:
"5+3"
"10-40"
"10*3"
Tôi muốn tránh rất nhiều câu lệnh if-then-other. Tôi có thể làm cái này như thế nào?
Tôi đang cố gắng viết một thói quen Java để đánh giá các biểu thức toán học đơn giản từ String
các giá trị như:
"5+3"
"10-40"
"10*3"
Tôi muốn tránh rất nhiều câu lệnh if-then-other. Tôi có thể làm cái này như thế nào?
Câu trả lời:
Với JDK1.6, bạn có thể sử dụng công cụ Javascript tích hợp.
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
public class Test {
public static void main(String[] args) throws ScriptException {
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String foo = "40+2";
System.out.println(engine.eval(foo));
}
}
return (Double) engine.eval(foo);
new javax.script.ScriptEngineManager().getEngineByName("JavaScript") .eval("var f = new java.io.FileWriter('hello.txt'); f.write('UNLIMITED POWER!'); f.close();");
- sẽ ghi một tệp qua JavaScript vào (theo mặc định) thư mục hiện tại của chương trình
Tôi đã viết eval
phương pháp này cho các biểu thức số học để trả lời câu hỏi này. Nó không cộng, trừ, nhân, chia, lũy thừa (sử dụng ^
ký hiệu) và một vài chức năng cơ bản như sqrt
. Nó hỗ trợ nhóm bằng cách sử dụng (
... )
, và nó được các nhà điều hành ưu tiên và quy tắc kết hợp chính xác.
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 throw new RuntimeException("Unknown function: " + func);
} else {
throw new RuntimeException("Unexpected: " + (char)ch);
}
if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation
return x;
}
}.parse();
}
Thí dụ:
System.out.println(eval("((4 - 2^3 + 1) * -sqrt(3*3+4*4)) / 2"));
Đầu ra: 7.5 (đúng)
Trình phân tích cú pháp là một trình phân tích cú pháp gốc đệ quy , do đó, bên trong sử dụng các phương thức phân tích cú pháp riêng biệt cho từng cấp độ ưu tiên của toán tử trong ngữ pháp của nó. Tôi giữ nó ngắn gọn để dễ sửa đổi, nhưng đây là một số ý tưởng bạn có thể muốn mở rộng nó với:
Biến:
Có thể dễ dàng thay đổi bit của trình phân tích cú pháp đọc tên cho các hàm để xử lý các biến tùy chỉnh, bằng cách tìm kiếm các tên trong bảng biến được truyền cho eval
phương thức, chẳng hạn như a Map<String,Double> variables
.
Biên soạn và đánh giá riêng biệt:
Điều gì sẽ xảy ra nếu, khi thêm hỗ trợ cho các biến, bạn muốn đánh giá cùng một biểu thức hàng triệu lần với các biến đã thay đổi mà không cần phân tích cú pháp mỗi lần? Điều đó là có thể. Trước tiên, xác định một giao diện sẽ sử dụng để đánh giá biểu thức được biên dịch trước:
@FunctionalInterface
interface Expression {
double eval();
}
Bây giờ thay đổi tất cả các phương thức trả về double
s, vì vậy thay vào đó chúng trả về một thể hiện của giao diện đó. Cú pháp lambda của Java 8 hoạt động rất tốt cho việc này. Ví dụ về một trong những phương thức đã thay đổi:
Expression parseExpression() {
Expression x = parseTerm();
for (;;) {
if (eat('+')) { // addition
Expression a = x, b = parseTerm();
x = (() -> a.eval() + b.eval());
} else if (eat('-')) { // subtraction
Expression a = x, b = parseTerm();
x = (() -> a.eval() - b.eval());
} else {
return x;
}
}
}
Điều đó xây dựng một cây đệ quy của Expression
các đối tượng đại diện cho biểu thức được biên dịch (một cây cú pháp trừu tượng ). Sau đó, bạn có thể biên dịch nó một lần và đánh giá nó nhiều lần với các giá trị khác nhau:
public static void main(String[] args) {
Map<String,Double> variables = new HashMap<>();
Expression exp = parse("x^2 - x + 2", variables);
for (double x = -20; x <= +20; x++) {
variables.put("x", x);
System.out.println(x + " => " + exp.eval());
}
}
Các kiểu dữ liệu khác nhau:
Thay vì double
, bạn có thể thay đổi người đánh giá để sử dụng một cái gì đó mạnh hơn như BigDecimal
, hoặc một lớp thực hiện các số phức hoặc số hữu tỷ (phân số). Bạn thậm chí có thể sử dụng Object
, cho phép kết hợp một số kiểu dữ liệu trong các biểu thức, giống như một ngôn ngữ lập trình thực sự. :)
Tất cả các mã trong câu trả lời này được phát hành cho miền công cộng . Chúc vui vẻ!
double x = parseTerm();
đánh giá toán tử bên trái, sau khi for (;;) {...}
đánh giá các hoạt động thành công của mức đặt hàng thực tế (cộng, trừ). Logic tương tự là và trong phương pháp parseTerm. ParseFactor không có cấp độ tiếp theo, do đó, chỉ có các đánh giá về các phương thức / biến hoặc trong trường hợp parantulation - đánh giá biểu thức con. Các boolean eat(int charToEat)
bình đẳng phương pháp kiểm tra của nhân vật con trỏ hiện tại với nhân vật charToEat, nếu trở lại bằng đúng và di chuyển con trỏ đến ký tự tiếp theo, tôi sử dụng tên 'chấp nhận' cho điều đó.
Cách chính xác để giải quyết vấn đề này là với một lexer và một trình phân tích cú pháp . Bạn có thể tự viết các phiên bản đơn giản của chúng hoặc các trang đó cũng có liên kết đến các trình phân tích và trình phân tích cú pháp Java.
Tạo một trình phân tích cú pháp gốc đệ quy là một bài tập học tập thực sự tốt.
Đối với dự án đại học của tôi, tôi đã tìm kiếm một trình phân tích cú pháp / đánh giá hỗ trợ cả các công thức cơ bản và các phương trình phức tạp hơn (đặc biệt là các toán tử lặp). Tôi tìm thấy thư viện mã nguồn mở rất đẹp cho JAVA và .NET được gọi là mXparser. Tôi sẽ đưa ra một vài ví dụ để tạo cảm giác về cú pháp, để được hướng dẫn thêm, vui lòng truy cập trang web của dự án (đặc biệt là phần hướng dẫn).
https://mathparser.org/mxparser-tutorial/
Và một vài ví dụ
1 - Furmula đơn giản
Expression e = new Expression("( 2 + 3/4 + sin(pi) )/2");
double v = e.calculate()
2 - Các đối số và hằng số do người dùng định nghĩa
Argument x = new Argument("x = 10");
Constant a = new Constant("a = pi^2");
Expression e = new Expression("cos(a*x)", x, a);
double v = e.calculate()
3 - Hàm do người dùng xác định
Function f = new Function("f(x, y, z) = sin(x) + cos(y*z)");
Expression e = new Expression("f(3,2,5)", f);
double v = e.calculate()
4 - Lặp lại
Expression e = new Expression("sum( i, 1, 100, sin(i) )");
double v = e.calculate()
Được tìm thấy gần đây - trong trường hợp bạn muốn thử cú pháp (và xem trường hợp sử dụng nâng cao), bạn có thể tải xuống ứng dụng Máy tính vô hướng được cung cấp bởi mXparser.
Trân trọng
ĐÂY là một thư viện mã nguồn mở khác trên GitHub có tên EvalEx.
Không giống như công cụ JavaScript, thư viện này chỉ tập trung vào đánh giá các biểu thức toán học. Hơn nữa, thư viện có thể mở rộng và hỗ trợ sử dụng các toán tử boolean cũng như dấu ngoặc đơn.
Bạn cũng có thể thử trình thông dịch BeanShell :
Interpreter interpreter = new Interpreter();
interpreter.eval("result = (7+21*6)/(32-27)");
System.out.println(interpreter.get("result"));
Bạn có thể dễ dàng đánh giá các biểu thức nếu ứng dụng Java của bạn đã truy cập cơ sở dữ liệu mà không cần sử dụng bất kỳ JAR nào khác.
Một số cơ sở dữ liệu yêu cầu bạn sử dụng bảng giả (ví dụ: bảng "kép" của Oracle) và các cơ sở dữ liệu khác sẽ cho phép bạn đánh giá các biểu thức mà không "chọn" từ bất kỳ bảng nào.
Ví dụ: trong Sql Server hoặc Sqlite
select (((12.10 +12.0))/ 233.0) amount
và trong Oracle
select (((12.10 +12.0))/ 233.0) amount from dual;
Ưu điểm của việc sử dụng DB là bạn có thể đánh giá nhiều biểu thức cùng một lúc. Ngoài ra, hầu hết các DB sẽ cho phép bạn sử dụng các biểu thức rất phức tạp và cũng sẽ có một số hàm bổ sung có thể được gọi là cần thiết.
Tuy nhiên, hiệu suất có thể bị ảnh hưởng nếu nhiều biểu thức đơn lẻ cần được đánh giá riêng lẻ, đặc biệt khi DB được đặt trên máy chủ mạng.
Phần sau đây giải quyết vấn đề hiệu năng ở một mức độ nào đó, bằng cách sử dụng cơ sở dữ liệu trong bộ nhớ Sqlite.
Đây là một ví dụ hoạt động đầy đủ trong Java
Class. forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite::memory:");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount");
rs.next();
System.out.println(rs.getBigDecimal(1));
stat.close();
conn.close();
Tất nhiên bạn có thể mở rộng mã trên để xử lý nhiều phép tính cùng một lúc.
ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount, (1+100)/20.0 amount2");
Bài viết này thảo luận về các phương pháp khác nhau. Dưới đây là 2 cách tiếp cận chính được đề cập trong bài viết:
Cho phép các tập lệnh bao gồm các tham chiếu đến các đối tượng java.
// Create or retrieve a JexlEngine
JexlEngine jexl = new JexlEngine();
// Create an expression object
String jexlExp = "foo.innerFoo.bar()";
Expression e = jexl.createExpression( jexlExp );
// Create a context and add data
JexlContext jctx = new MapContext();
jctx.set("foo", new Foo() );
// Now evaluate the expression, getting the result
Object o = e.evaluate(jctx);
private static void jsEvalWithVariable()
{
List<String> namesList = new ArrayList<String>();
namesList.add("Jill");
namesList.add("Bob");
namesList.add("Laureen");
namesList.add("Ed");
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");
jsEngine.put("namesListKey", namesList);
System.out.println("Executing in script environment...");
try
{
jsEngine.eval("var x;" +
"var names = namesListKey.toArray();" +
"for(x in names) {" +
" println(names[x]);" +
"}" +
"namesListKey.add(\"Dana\");");
}
catch (ScriptException ex)
{
ex.printStackTrace();
}
}
Một cách khác là sử dụng Spring Expression Language hoặc SpEL, điều này thực hiện nhiều hơn cùng với việc đánh giá các biểu thức toán học do đó có thể hơi quá mức cần thiết. Bạn không phải sử dụng Spring framework để sử dụng thư viện biểu thức này vì nó là độc lập. Sao chép các ví dụ từ tài liệu của SpEL:
ExpressionParser parser = new SpelExpressionParser();
int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2
double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); //24.0
Đọc thêm các ví dụ SpEL súc tích ở đây và các tài liệu đầy đủ ở đây
nếu chúng ta sẽ thực hiện nó thì chúng ta có thể sử dụng thuật toán dưới đây: -
Trong khi vẫn còn các mã thông báo để đọc,
1.1 Nhận mã thông báo tiếp theo. 1.2 Nếu mã thông báo là:
1.2.1 Một số: đẩy nó lên ngăn xếp giá trị.
1.2.2 Một biến: lấy giá trị của nó và đẩy lên ngăn xếp giá trị.
1.2.3 Dấu ngoặc đơn bên trái: đẩy nó vào ngăn xếp toán tử.
1.2.4 Một dấu ngoặc đơn đúng:
1 While the thing on top of the operator stack is not a
left parenthesis,
1 Pop the operator from the operator stack.
2 Pop the value stack twice, getting two operands.
3 Apply the operator to the operands, in the correct order.
4 Push the result onto the value stack.
2 Pop the left parenthesis from the operator stack, and discard it.
1.2.5 Một toán tử (gọi nó là thisOp):
1 While the operator stack is not empty, and the top thing on the
operator stack has the same or greater precedence as thisOp,
1 Pop the operator from the operator stack.
2 Pop the value stack twice, getting two operands.
3 Apply the operator to the operands, in the correct order.
4 Push the result onto the value stack.
2 Push thisOp onto the operator stack.
Trong khi ngăn xếp toán tử không trống, 1 Pop toán tử từ ngăn xếp toán tử. 2 Pop ngăn xếp giá trị hai lần, nhận hai toán hạng. 3 Áp dụng toán tử cho toán hạng, theo đúng thứ tự. 4 Đẩy kết quả lên ngăn xếp giá trị.
Tại thời điểm này, ngăn xếp toán tử sẽ trống và ngăn xếp giá trị chỉ có một giá trị trong đó, đó là kết quả cuối cùng.
Đây là một thay thế thú vị khác https://github.com/Shy-Ta/expression-evaluator-demo
Việc sử dụng rất đơn giản và hoàn thành công việc, ví dụ:
ExpressionsEvaluator evalExpr = ExpressionsFactory.create("2+3*4-6/2");
assertEquals(BigDecimal.valueOf(11), evalExpr.eval());
Tôi nghĩ rằng bất cứ cách nào bạn làm điều này sẽ liên quan đến rất nhiều tuyên bố có điều kiện. Nhưng đối với các hoạt động đơn lẻ như trong ví dụ của bạn, bạn có thể giới hạn ở mức 4 nếu các câu lệnh có nội dung như
String math = "1+4";
if (math.split("+").length == 2) {
//do calculation
} else if (math.split("-").length == 2) {
//do calculation
} ...
Nó phức tạp hơn nhiều khi bạn muốn xử lý nhiều thao tác như "4 + 5 * 6".
Nếu bạn đang cố gắng xây dựng một máy tính thì tôi sẽ vượt qua từng phần của phép tính một cách riêng biệt (mỗi số hoặc toán tử) thay vì dưới dạng một chuỗi.
Quá muộn để trả lời nhưng tôi đã gặp tình huống tương tự để đánh giá biểu thức trong java, nó có thể giúp ai đó
MVEL
không đánh giá thời gian chạy của các biểu thức, chúng ta có thể viết mã java String
để đánh giá nó trong này.
String expressionStr = "x+y";
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("x", 10);
vars.put("y", 20);
ExecutableStatement statement = (ExecutableStatement) MVEL.compileExpression(expressionStr);
Object result = MVEL.executeExpression(statement, vars);
Bạn có thể có một cái nhìn vào khung Symja :
ExprEvaluator util = new ExprEvaluator();
IExpr result = util.evaluate("10-40");
System.out.println(result.toString()); // -> "-30"
Lưu ý rằng các biểu thức phức tạp hơn chắc chắn có thể được đánh giá:
// D(...) gives the derivative of the function Sin(x)*Cos(x)
IAST function = D(Times(Sin(x), Cos(x)), x);
IExpr result = util.evaluate(function);
// print: Cos(x)^2-Sin(x)^2
Hãy thử mã mẫu sau bằng cách sử dụng công cụ Javascript của JDK1.6 với xử lý tiêm mã.
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class EvalUtil {
private static ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
public static void main(String[] args) {
try {
System.out.println((new EvalUtil()).eval("(((5+5)/2) > 5) || 5 >3 "));
System.out.println((new EvalUtil()).eval("(((5+5)/2) > 5) || true"));
} catch (Exception e) {
e.printStackTrace();
}
}
public Object eval(String input) throws Exception{
try {
if(input.matches(".*[a-zA-Z;~`#$_{}\\[\\]:\\\\;\"',\\.\\?]+.*")) {
throw new Exception("Invalid expression : " + input );
}
return engine.eval(input);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
Điều này thực sự bổ sung cho câu trả lời được đưa ra bởi @Boann. Nó có một lỗi nhỏ khiến "-2 ^ 2" đưa ra kết quả sai lệch là -4.0. Vấn đề cho điều đó là điểm tại đó lũy thừa được đánh giá theo giá trị của nó. Chỉ cần di chuyển số mũ sang khối parseTerm (), và bạn sẽ ổn thôi. Hãy xem bên dưới, đây là câu trả lời của @ Boann được sửa đổi đôi chút. Sửa đổi là trong các ý kiến.
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 if (eat('^')) x = Math.pow(x, parseFactor()); //exponentiation -> Moved in to here. So the problem is fixed
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 throw new RuntimeException("Unknown function: " + func);
} else {
throw new RuntimeException("Unexpected: " + (char)ch);
}
//if (eat('^')) x = Math.pow(x, parseFactor()); // exponentiation -> This is causing a bit of problem
return x;
}
}.parse();
}
-2^2 = -4
là thực sự bình thường, và không phải là một lỗi. Nó được nhóm như thế nào -(2^2)
. Hãy thử nó trên Desmos, ví dụ. Mã của bạn thực sự giới thiệu một số lỗi. Đầu tiên là ^
không còn các nhóm từ phải sang trái. Nói cách khác, 2^3^2
được cho là nhóm thích 2^(3^2)
vì ^
là liên kết đúng, nhưng sửa đổi của bạn làm cho nhóm thích (2^3)^2
. Thứ hai là được cho ^
là có quyền ưu tiên cao hơn *
và /
, nhưng các sửa đổi của bạn đối xử với nó như nhau. Xem ideone.com/iN2mMa .
package ExpressionCalculator.expressioncalculator;
import java.text.DecimalFormat;
import java.util.Scanner;
public class ExpressionCalculator {
private static String addSpaces(String exp){
//Add space padding to operands.
//https://regex101.com/r/sJ9gM7/73
exp = exp.replaceAll("(?<=[0-9()])[\\/]", " / ");
exp = exp.replaceAll("(?<=[0-9()])[\\^]", " ^ ");
exp = exp.replaceAll("(?<=[0-9()])[\\*]", " * ");
exp = exp.replaceAll("(?<=[0-9()])[+]", " + ");
exp = exp.replaceAll("(?<=[0-9()])[-]", " - ");
//Keep replacing double spaces with single spaces until your string is properly formatted
/*while(exp.indexOf(" ") != -1){
exp = exp.replace(" ", " ");
}*/
exp = exp.replaceAll(" {2,}", " ");
return exp;
}
public static Double evaluate(String expr){
DecimalFormat df = new DecimalFormat("#.####");
//Format the expression properly before performing operations
String expression = addSpaces(expr);
try {
//We will evaluate using rule BDMAS, i.e. brackets, division, power, multiplication, addition and
//subtraction will be processed in following order
int indexClose = expression.indexOf(")");
int indexOpen = -1;
if (indexClose != -1) {
String substring = expression.substring(0, indexClose);
indexOpen = substring.lastIndexOf("(");
substring = substring.substring(indexOpen + 1).trim();
if(indexOpen != -1 && indexClose != -1) {
Double result = evaluate(substring);
expression = expression.substring(0, indexOpen).trim() + " " + result + " " + expression.substring(indexClose + 1).trim();
return evaluate(expression.trim());
}
}
String operation = "";
if(expression.indexOf(" / ") != -1){
operation = "/";
}else if(expression.indexOf(" ^ ") != -1){
operation = "^";
} else if(expression.indexOf(" * ") != -1){
operation = "*";
} else if(expression.indexOf(" + ") != -1){
operation = "+";
} else if(expression.indexOf(" - ") != -1){ //Avoid negative numbers
operation = "-";
} else{
return Double.parseDouble(expression);
}
int index = expression.indexOf(operation);
if(index != -1){
indexOpen = expression.lastIndexOf(" ", index - 2);
indexOpen = (indexOpen == -1)?0:indexOpen;
indexClose = expression.indexOf(" ", index + 2);
indexClose = (indexClose == -1)?expression.length():indexClose;
if(indexOpen != -1 && indexClose != -1) {
Double lhs = Double.parseDouble(expression.substring(indexOpen, index));
Double rhs = Double.parseDouble(expression.substring(index + 2, indexClose));
Double result = null;
switch (operation){
case "/":
//Prevent divide by 0 exception.
if(rhs == 0){
return null;
}
result = lhs / rhs;
break;
case "^":
result = Math.pow(lhs, rhs);
break;
case "*":
result = lhs * rhs;
break;
case "-":
result = lhs - rhs;
break;
case "+":
result = lhs + rhs;
break;
default:
break;
}
if(indexClose == expression.length()){
expression = expression.substring(0, indexOpen) + " " + result + " " + expression.substring(indexClose);
}else{
expression = expression.substring(0, indexOpen) + " " + result + " " + expression.substring(indexClose + 1);
}
return Double.valueOf(df.format(evaluate(expression.trim())));
}
}
}catch(Exception exp){
exp.printStackTrace();
}
return 0.0;
}
public static void main(String args[]){
Scanner scanner = new Scanner(System.in);
System.out.print("Enter an Mathematical Expression to Evaluate: ");
String input = scanner.nextLine();
System.out.println(evaluate(input));
}
}
Còn những thứ như thế này thì sao:
String st = "10+3";
int result;
for(int i=0;i<st.length();i++)
{
if(st.charAt(i)=='+')
{
result=Integer.parseInt(st.substring(0, i))+Integer.parseInt(st.substring(i+1, st.length()));
System.out.print(result);
}
}
và làm điều tương tự cho mọi toán tử toán học khác cho phù hợp ..
Có thể chuyển đổi bất kỳ chuỗi biểu thức nào trong ký hiệu infix thành ký hiệu hậu tố bằng thuật toán shunting-yard của Djikstra . Kết quả của thuật toán sau đó có thể đóng vai trò là đầu vào cho thuật toán postfix với trả về kết quả của biểu thức.
Tôi đã viết một bài viết về nó ở đây, với một triển khai trong java
Còn một lựa chọn khác: https://github.com/stefanhaustein/expressionparser
Tôi đã thực hiện điều này để có một tùy chọn đơn giản nhưng linh hoạt để cho phép cả hai:
TreeBuilder được liên kết ở trên là một phần của gói demo CAS thực hiện dẫn xuất tượng trưng. Ngoài ra còn có một ví dụ về trình thông dịch BASIC và tôi đã bắt đầu xây dựng trình thông dịch TypeScript bằng cách sử dụng nó.
Một lớp Java có thể đánh giá các biểu thức toán học:
package test;
public class Calculator {
public static Double calculate(String expression){
if (expression == null || expression.length() == 0) {
return null;
}
return calc(expression.replace(" ", ""));
}
public static Double calc(String expression) {
if (expression.startsWith("(") && expression.endsWith(")")) {
return calc(expression.substring(1, expression.length() - 1));
}
String[] containerArr = new String[]{expression};
double leftVal = getNextOperand(containerArr);
expression = containerArr[0];
if (expression.length() == 0) {
return leftVal;
}
char operator = expression.charAt(0);
expression = expression.substring(1);
while (operator == '*' || operator == '/') {
containerArr[0] = expression;
double rightVal = getNextOperand(containerArr);
expression = containerArr[0];
if (operator == '*') {
leftVal = leftVal * rightVal;
} else {
leftVal = leftVal / rightVal;
}
if (expression.length() > 0) {
operator = expression.charAt(0);
expression = expression.substring(1);
} else {
return leftVal;
}
}
if (operator == '+') {
return leftVal + calc(expression);
} else {
return leftVal - calc(expression);
}
}
private static double getNextOperand(String[] exp){
double res;
if (exp[0].startsWith("(")) {
int open = 1;
int i = 1;
while (open != 0) {
if (exp[0].charAt(i) == '(') {
open++;
} else if (exp[0].charAt(i) == ')') {
open--;
}
i++;
}
res = calc(exp[0].substring(1, i - 1));
exp[0] = exp[0].substring(i);
} else {
int i = 1;
if (exp[0].charAt(0) == '-') {
i++;
}
while (exp[0].length() > i && isNumber((int) exp[0].charAt(i))) {
i++;
}
res = Double.parseDouble(exp[0].substring(0, i));
exp[0] = exp[0].substring(i);
}
return res;
}
private static boolean isNumber(int c) {
int zero = (int) '0';
int nine = (int) '9';
return (c >= zero && c <= nine) || c =='.';
}
public static void main(String[] args) {
System.out.println(calculate("(((( -6 )))) * 9 * -1"));
System.out.println(calc("(-5.2+-5*-5*((5/4+2)))"));
}
}
Thư viện bên ngoài như RHINO hoặc NASHORN có thể được sử dụng để chạy javascript. Và javascript có thể đánh giá công thức đơn giản mà không cần ghép chuỗi. Không có tác động hiệu suất là tốt nếu mã được viết tốt. Dưới đây là một ví dụ với RHINO -
public class RhinoApp {
private String simpleAdd = "(12+13+2-2)*2+(12+13+2-2)*2";
public void runJavaScript() {
Context jsCx = Context.enter();
Context.getCurrentContext().setOptimizationLevel(-1);
ScriptableObject scope = jsCx.initStandardObjects();
Object result = jsCx.evaluateString(scope, simpleAdd , "formula", 0, null);
Context.exit();
System.out.println(result);
}
import java.util.*;
public class check {
int ans;
String str="7 + 5";
StringTokenizer st=new StringTokenizer(str);
int v1=Integer.parseInt(st.nextToken());
String op=st.nextToken();
int v2=Integer.parseInt(st.nextToken());
if(op.equals("+")) { ans= v1 + v2; }
if(op.equals("-")) { ans= v1 - v2; }
//.........
}