Auswerten eines mathematischen Ausdrucks in String-Form

Ich versuche, eine Java-Routine zu schreiben, um einfache mathematische Ausdrücke aus String Werten wie:

  1. "5+3"
  2. "10-40"
  3. "10*3"

Ich möchte viele if-then-else-Aussagen vermeiden. Wie kann ich das machen?

Mit JDK1.6 können Sie die integrierte Javascript-Engine verwenden.

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

Ich habe diese eval Methode für arithmetische Ausdrücke geschrieben, um diese Frage zu beantworten. Es macht Addition, Subtraktion, Multiplikation, Division, Potenzierung (mit dem ^ -Symbol) und ein paar Grundfunktionen wie sqrt . Es unterstützt die Gruppierung mit () , und es erhält die Operator- Vorrang- und Assoziativitätsregeln korrekt.

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

Beispiel:

 System.out.println(eval("((4 - 2^3 + 1) * -sqrt(3*3+4*4)) / 2")); 

Ausgabe: 7,5 (was korrekt ist)


Der Parser ist ein rekursiver Sink-Parser , verwendet also intern für jede Stufe der Operatorpräzedenz in seiner Grammatik separate Analyseverfahren. Ich habe es kurz gehalten, so dass es leicht zu ändern ist, aber hier sind einige Ideen, mit denen Sie es vielleicht erweitern möchten:

  • Variablen:

    Das Bit des Parsers, das die Namen für functionen liest, kann leicht geändert werden, um auch benutzerdefinierte Variablen zu verarbeiten, indem nach Namen in einer Variablentabelle gesucht wird, die an die eval Methode übergeben wird, z. B. Map variables .

  • Separate Zusammenstellung und Auswertung:

    Was wäre, wenn Sie, nachdem Sie Unterstützung für Variablen hinzugefügt haben, den gleichen Ausdruck Millionen Male mit geänderten Variablen auswerten möchten, ohne ihn jedes Mal zu analysieren? Es ist möglich. Definieren Sie zuerst eine Schnittstelle, die verwendet werden soll, um den vorkompilierten Ausdruck auszuwerten:

     @FunctionalInterface interface Expression { double eval(); } 

    Ändern Sie nun alle Methoden, die double s zurückgeben, also geben sie stattdessen eine Instanz dieser Schnittstelle zurück. Die Lambda-Syntax von Java 8 funktioniert dafür hervorragend. Beispiel für eine der geänderten Methoden:

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

    Dadurch wird eine rekursive Struktur von Expression Objekten erstellt, die den kompilierten Ausdruck (einen abstrakten Syntaxbaum ) darstellen. Dann können Sie es einmal kompilieren und mehrfach mit verschiedenen Werten auswerten:

     public static void main(String[] args) { Map 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()); } } 
  • Verschiedene Datentypen:

    Anstelle von double können Sie das Auswertungsprogramm so ändern, dass es etwas BigDecimal wie BigDecimal oder eine class verwendet, die komplexe Zahlen oder rationale Zahlen (Brüche) implementiert. Sie könnten sogar Object , was eine Mischung von Datentypen in Ausdrücken erlaubt, genau wie eine echte Programmiersprache. 🙂


Der gesamte Code in dieser Antwort wurde für die Public Domain freigegeben. Habe Spaß!

Der richtige Weg, dies zu lösen, ist mit einem Lexer und einem Parser . Sie können einfache Versionen dieser selbst schreiben, oder diese Seiten haben auch Links zu Java-Lexer und Parsern.

Einen rekursiven Sinkparser zu erstellen, ist eine wirklich gute Lernübung.

HERE ist eine weitere Open-Source-Bibliothek auf GitHub namens EvalEx.

Im Gegensatz zur JavaScript-Engine konzentriert sich diese Bibliothek nur auf die Auswertung mathematischer Ausdrücke. Darüber hinaus ist die Bibliothek erweiterbar und unterstützt die Verwendung von booleschen Operatoren sowie Klammern.

Sie können auch den BeanShell- Interpreter ausprobieren:

 Interpreter interpreter = new Interpreter(); interpreter.eval("result = (7+21*6)/(32-27)"); System.out.println(interpreter.get("result")); 

Sie können Ausdrücke leicht auswerten, wenn Ihre Java-Anwendung bereits auf eine database zugreift, ohne andere JARs zu verwenden.

Bei einigen databaseen müssen Sie eine Dummy-Tabelle verwenden (z. B. die “duale” Tabelle von Oracle), bei anderen databaseen können Sie Ausdrücke auswerten, ohne aus einer Tabelle “auswählen” zu müssen.

Zum Beispiel in SQL Server oder SQLite

 select (((12.10 +12.0))/ 233.0) amount 

und in Oracle

 select (((12.10 +12.0))/ 233.0) amount from dual; 

Der Vorteil der Verwendung einer database besteht darin, dass Sie viele Ausdrücke gleichzeitig auswerten können. Die meisten DBs erlauben es Ihnen auch, hochkomplexe Ausdrücke zu verwenden und haben auch eine Reihe von zusätzlichen functionen, die bei Bedarf aufgerufen werden können.

Die performance kann jedoch leiden, wenn viele einzelne Ausdrücke einzeln ausgewertet werden müssen, insbesondere wenn sich die database auf einem Netzwerkserver befindet.

Im Folgenden wird das performancesproblem einigermaßen behandelt, indem eine Sqlite In-Memory-database verwendet wird.

Hier ist ein voll funktionsfähiges Beispiel in 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(); 

Natürlich können Sie den obigen Code erweitern, um mehrere Berechnungen gleichzeitig zu verarbeiten.

 ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount, (1+100)/20.0 amount2"); 

Für mein Universitätsprojekt suchte ich nach einem Parser / Evaluator, der sowohl grundlegende Formeln als auch kompliziertere Gleichungen (insbesondere iterierte Operatoren) unterstützt. Ich habe eine sehr nette Open-Source-Bibliothek für JAVA und .NET namens mXparser gefunden. Ich werde ein paar Beispiele geben, um ein Gefühl für die Syntax zu bekommen, für weitere statementen besuchen Sie bitte die Projektwebseite (besonders den Tutorialbereich).

http://mathparser.org/

http://mathparser.org/mxparser-tutorial/

http://mathparser.org/api/

Und ein paar Beispiele

1 – Einfache Färmula

 Expression e = new Expression("( 2 + 3/4 + sin(pi) )/2"); double v = e.calculate() 

2 – Benutzerdefinierte Argumente und Konstanten

 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 – Benutzerdefinierte functionen

 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 – Iteration

 Expression e = new Expression("sum( i, 1, 100, sin(i) )"); double v = e.calculate() 

Freundliche Grüße

Dieser Artikel weist auf drei verschiedene Ansätze hin: JEXL von Apache und Skripts, die Referenzen zu Java-Objekten enthalten.

Eine andere Möglichkeit ist die Verwendung von Spring Expression Language oder SpEL, die viel mehr mit der Auswertung von mathematischen Ausdrücken zu tun haben, daher vielleicht etwas übertrieben. Sie müssen das Spring-Framework nicht verwenden, um diese Expressions-Bibliothek zu verwenden, da sie eigenständig ist. Kopieren von Beispielen aus der SPEL-Dokumentation:

 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 

Lesen Sie hier mehr prägnante SpEL-Beispiele und die vollständigen Dokumente hier

Dies ist eine weitere interessante Alternative https://github.com/Shy-Ta/expression-evaluator-demo

Die Verwendung ist sehr einfach und erledigt die Arbeit, zum Beispiel:

  ExpressionsEvaluator evalExpr = ExpressionsFactory.create("2+3*4-6/2"); assertEquals(BigDecimal.valueOf(11), evalExpr.eval()); 

Ich denke, was auch immer Sie tun, es wird eine Menge von bedingten Aussagen beinhalten. Aber für einzelne Operationen wie in Ihren Beispielen könnten Sie es auf 4 if-statementen mit etwas wie beschränken

 String math = "1+4"; if (math.split("+").length == 2) { //do calculation } else if (math.split("-").length == 2) { //do calculation } ... 

Es wird viel komplizierter, wenn Sie mit mehreren Operationen wie “4 + 5 * 6” arbeiten wollen.

Wenn Sie versuchen, einen Taschenrechner zu bauen, würde ich jeden Abschnitt der Berechnung separat (jede Zahl oder Operator) statt als eine einzelne Zeichenfolge überschreiten.

Es scheint, als ob JEP die Arbeit machen sollte

Wenn wir es implementieren, können wir den folgenden Algorithmus verwenden:

  1. Während noch Token eingelesen werden müssen,

    1.1 Holen Sie das nächste Token. 1.2 Wenn das Token ist:

    1.2.1 Eine Zahl: schieben Sie sie auf den Wertestapel.

    1.2.2 Eine Variable: Erhalten Sie ihren Wert und drücken Sie auf den Wertestapel.

    1.2.3 Eine linke Klammer: Schieben Sie sie auf den Operator-Stapel.

    1.2.4 Eine rechte runde Klammer:

      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 Ein Operator (nennen Sie es 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. 
  2. Während der Operatorstapel nicht leer ist, 1 Klappen Sie den Operator vom Operatorstapel auf. 2 Klappen Sie den Werte-Stack zweimal auf und erhalten Sie zwei Operanden. 3 Wenden Sie den Operator in der richtigen Reihenfolge auf die Operanden an. 4 Drücken Sie das Ergebnis auf den Wertestapel.

  3. An diesem Punkt sollte der Operatorstapel leer sein und der Wertstapel sollte nur einen Wert enthalten, was das Endergebnis ist.

Vielleicht sehen Sie sich das Symja-Framework an :

 ExprEvaluator util = new ExprEvaluator(); IExpr result = util.evaluate("10-40"); System.out.println(result.toString()); // -> "-30" 

Beachten Sie, dass definitiv komplexere Ausdrücke ausgewertet werden können:

 // 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 

Probieren Sie den folgenden Beispielcode mit der JavaScript-Engine von JDK1.6 mit der Code-Injection-Behandlung aus.

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

Dies ergänzt die Antwort von @Boann. Es hat einen leichten Fehler, der bewirkt, dass “-2 ^ 2” ein errorshaftes Ergebnis von -4.0 ergibt. Das Problem dafür ist der Punkt, an dem die Potenzierung in seinem ausgewertet wird. Verschieben Sie einfach die Potenzierung in den Block von parseTerm (), und alles wird gut. Schau dir das unten an, was @ Boanns Antwort leicht modifiziert ist. Änderung ist in den Kommentaren.

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

}

Wie wäre es mit so etwas:

 String st = "10+3"; int result; for(int i=0;i 

und mach das Gleiche für jeden anderen mathematischen Operator entsprechend ..

Es ist möglich, jeden Ausdrucksstring in Infix-Notation in eine Postfix-Notation umzuwandeln, indem man den Shunting-Yard-Algorithmus von Djikstra verwendet . Das Ergebnis des Algorithmus kann dann als Eingabe für den Postfix-Algorithmus dienen, wobei das Ergebnis des Ausdrucks zurückgegeben wird.

Ich habe hier einen Artikel geschrieben , mit einer Implementierung in Java

Es ist zu spät, um zu antworten, aber ich stieß auf die gleiche Situation, um den Ausdruck in Java zu bewerten, es könnte jemandem helfen

MVEL führt eine Laufzeitbewertung von Ausdrücken durch, wir können einen Java-Code in String schreiben, um ihn in diesem zu evaluieren.

  String expressionStr = "x+y"; Map vars = new HashMap(); vars.put("x", 10); vars.put("y", 20); ExecutableStatement statement = (ExecutableStatement) MVEL.compileExpression(expressionStr); Object result = MVEL.executeExpression(statement, vars); 
 import java.util.*; StringTokenizer st; int ans; public class check { 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; } //......... } 

Noch eine weitere Option: https://github.com/stefanhaustein/expressionsparser

Ich habe dies implementiert, um eine einfache, aber flexible Option zu haben, die beides erlaubt:

  • Sofortige Verarbeitung ( Calculator.java , SetDemo.java )
  • Erstellen und Verarbeiten eines Syntaxbaums ( TreeBuilder.java )

Der oben verlinkte TreeBuilder ist Teil eines CAS- Demopakets, das symbolische Herleitung durchführt. Es gibt auch ein BASIC-Interpreter- Beispiel und ich habe damit begonnen, einen TypeScript-Interpreter zu erstellen.

Externe Bibliotheken wie RHINO oder NASHORN können verwendet werden, um Javascript auszuführen. Und Javascript kann einfache Formel auswerten, ohne die Zeichenfolge zu parrieren. Keine performanceseinbußen, auch wenn der Code gut geschrieben ist. Unten ist ein Beispiel mit 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); } 

Eine Java-class, die mathematische Ausdrücke auswerten kann:

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