web-dev-qa-db-fra.com

Comment évaluer une expression mathématique donnée sous forme de chaîne?

J'essaie d'écrire une routine Java pour évaluer des expressions mathématiques simples à partir de valeurs String telles que:

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

Je veux éviter beaucoup de déclarations si-alors-sinon. Comment puis-je faire ceci?

289
Shah

Avec JDK1.6, vous pouvez utiliser le moteur Javascript intégré.

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

J'ai écrit cette méthode eval pour les expressions arithmétiques afin de répondre à cette question. Il fait l'addition, la soustraction, la multiplication, la division, l'exponentiation (à l'aide du symbole ^) et quelques fonctions de base comme sqrt. Il prend en charge le regroupement à l'aide de (...), et il obtient les règles de l'opérateur priorité et de l'associativité .

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

Exemple:

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

Sortie: 7.5 (ce qui est correct)


L'analyseur est un analyseur récursif de descente , donc utilise en interne des méthodes d'analyse distinctes pour chaque niveau de priorité des opérateurs dans sa grammaire. Je l'ai gardé court , donc c'est facile à modifier, mais voici quelques idées avec lesquelles vous voudrez peut-être développer:

  • Variables:

    Le bit de l'analyseur qui lit les noms de fonctions peut facilement être modifié pour gérer également les variables personnalisées, en recherchant les noms dans une table de variables transmise à la méthode eval, telle que Map<String,Double> variables.

  • Compilation et évaluation séparées:

    Et si, après avoir pris en charge les variables, vous vouliez évaluer la même expression des millions de fois avec des variables modifiées, sans l’analyser à chaque fois? C'est possible. Commencez par définir une interface à utiliser pour évaluer l'expression précompilée:

    @FunctionalInterface
    interface Expression {
        double eval();
    }
    

    Modifiez maintenant toutes les méthodes qui renvoient doubles. Par conséquent, elles renvoient une instance de cette interface. La syntaxe lambda de Java 8 fonctionne très bien pour cela. Exemple d'une des méthodes modifiées:

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

    Cela construit un arbre récursif de Expression objets représentant l'expression compilée (un arbre de syntaxe abstraite ). Ensuite, vous pouvez le compiler une fois et l’évaluer à plusieurs reprises avec différentes valeurs:

    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());
        }
    }
    
  • Différents types de données:

    Au lieu de double, vous pouvez demander à l'évaluateur d'utiliser quelque chose de plus puissant, tel que BigDecimal, ou une classe implémentant des nombres complexes ou des nombres rationnels (fractions). Vous pouvez même utiliser Object, permettant un mélange de types de données dans les expressions, comme un véritable langage de programmation. :)


Tout le code de cette réponse a été publié dans le domaine public . S'amuser!

200
Boann

La bonne façon de résoudre ce problème est d'utiliser un lexer et un analyseur . Vous pouvez écrire vous-même des versions simples de celles-ci, ou ces pages comportent également des liens vers Java lexers et analyseurs.

Créer un analyseur récursif de descente est un très bon exercice d'apprentissage.

29
Greg Hewgill

Pour mon projet universitaire, je recherchais un analyseur/évaluateur prenant en charge les formules de base et les équations plus complexes (en particulier les opérateurs itérés). J'ai trouvé une très belle bibliothèque open source pour Java et .NET appelée mXparser. Je vais donner quelques exemples pour vous aider à mieux comprendre la syntaxe. Pour plus d’informations, visitez le site Web du projet (section tutoriel en particulier).

http://mathparser.org/

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

http://mathparser.org/api/

Et quelques exemples

1 - Furmula simple

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

2 - Arguments et constantes définis par l'utilisateur

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 - Fonctions définies par l'utilisateur

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 - Itération

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

Trouvé récemment - au cas où vous voudriez essayer la syntaxe (et voir le cas d'utilisation avancée), vous pouvez télécharger le Calculatrice scalaireapp qui est optimisé par mXparser.

Meilleures salutations

19
Leroy Kegan

HERE est une autre bibliothèque open source sur GitHub appelée EvalEx.

Contrairement au moteur JavaScript, cette bibliothèque se concentre uniquement sur l'évaluation d'expressions mathématiques. De plus, la bibliothèque est extensible et supporte l'utilisation d'opérateurs booléens ainsi que de parenthèses.

18
Tanvir

Vous pouvez facilement évaluer des expressions si votre application Java accède déjà à une base de données, sans utiliser aucun autre JAR.

Certaines bases de données requièrent l'utilisation d'une table fictive (par exemple, la table "dual" d'Oracle) et d'autres vous permettront d'évaluer des expressions sans "sélectionner" dans une table.

Par exemple, dans Sql Server ou Sqlite

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

et dans Oracle

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

L'avantage d'utiliser une base de données est que vous pouvez évaluer plusieurs expressions en même temps. De plus, la plupart des bases de données vous permettront d’utiliser des expressions très complexes et comporteront un certain nombre de fonctions supplémentaires pouvant être appelées si nécessaire.

Toutefois, les performances risquent de souffrir si de nombreuses expressions uniques doivent être évaluées individuellement, en particulier lorsque la base de données est située sur un serveur de réseau.

Ce qui suit résout le problème de performances dans une certaine mesure, en utilisant une base de données en mémoire SQLite.

Voici un exemple complet de travail en 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();

Bien sûr, vous pouvez étendre le code ci-dessus pour gérer plusieurs calculs en même temps.

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

Vous pouvez également essayer l’interprète BeanShell :

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

Cet article discute de diverses approches. Voici les 2 approches clés mentionnées dans l'article:

JEXL d'Apache

Autorise les scripts incluant des références à des objets 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);

Utilisez le moteur javascript intégré dans le JDK:

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

Une autre méthode consiste à utiliser Spring Expression Language ou SpEL, qui évalue beaucoup plus l'évaluation des expressions mathématiques, donc peut-être un peu trop. Il n'est pas nécessaire d'utiliser le framework Spring pour utiliser cette bibliothèque d'expressions, car elle est autonome. Copier des exemples de la documentation de 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

Lire des exemples plus concis de SpEL ici et la documentation complète ici

7
Faheem Sohail

C'est une autre alternative intéressante https://github.com/Shy-Ta/expression-evaluator-demo

L'utilisation est très simple et fait le travail, par exemple:

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

si nous allons l'implémenter, alors nous pouvons utiliser l'algorithme ci-dessous: -

  1. Bien qu'il y ait encore des jetons à lire,

    1.1 Obtenez le prochain jeton. 1.2 Si le jeton est:

    1.2.1 Un nombre: Insérez-le dans la pile de valeurs.

    1.2.2 Une variable: récupère sa valeur et pousse sur la pile de valeurs.

    1.2.3 Une parenthèse gauche: poussez-la sur la pile d'opérateurs.

    1.2.4 Une parenthèse droite:

     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 Un opérateur (appelez-le 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. Tant que la pile d'opérateurs n'est pas vide, 1 Extraire l'opérateur de la pile d'opérateurs. 2 Pop la pile de valeurs deux fois, obtenant deux opérandes. 3 Appliquez l'opérateur aux opérandes dans le bon ordre. 4 Poussez le résultat sur la pile de valeurs.

  3. À ce stade, la pile d'opérateurs doit être vide et la pile de valeurs ne doit contenir qu'une seule valeur, à savoir le résultat final.

6
Prashant Gautam

Il semble que JEP devrait faire l'affaire

5
Bozho

Je pense que quelle que soit la façon dont vous faites cela, cela impliquera de nombreuses déclarations conditionnelles. Mais pour des opérations uniques comme dans vos exemples, vous pouvez le limiter à 4 si des instructions avec quelque chose comme

String math = "1+4";

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

Cela devient beaucoup plus compliqué lorsque vous souhaitez gérer plusieurs opérations telles que "4 + 5 * 6".

Si vous essayez de construire une calculatrice, je surestimerais chaque section du calcul séparément (chaque nombre ou opérateur) plutôt que sous la forme d'une chaîne unique.

4
BruteForce

Ceci complète en fait la réponse donnée par @Boann. Il y a un léger bug qui fait que "-2 ^ 2" donne un résultat erroné de -4.0. Le problème à cet égard est le point auquel l’exponentiation est évaluée dans le sien. Il suffit de déplacer l’exponentiation vers le bloc de parseTerm () et tout ira bien. Regardez ci-dessous, qui est réponse de @ Boann légèrement modifié. La modification est dans les commentaires.

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

}

3
chejaras

Vous pouvez jeter un oeil sur le framework Symja :

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

Notez que des expressions définitivement plus complexes peuvent être évaluées:

// 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
3
Laurent Magnin

Essayez l'exemple de code suivant en utilisant le moteur Javascript de JDK1.6 avec la gestion de l'injection de code.

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

Il est trop tard pour répondre mais je suis tombé sur la même situation pour évaluer l'expression en Java, cela pourrait aider quelqu'un

MVEL évalue les expressions à l'exécution, nous pouvons écrire un code Java dans String pour le faire évaluer.

    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);
2
Saravana

Que diriez-vous quelque chose comme ça:

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

et faire la même chose pour tous les autres opérateurs mathématiques en conséquence.

1
konxie

Une bibliothèque externe comme RHINO ou NASHORN peut être utilisée pour exécuter javascript. Et javascript peut évaluer une formule simple sans relier la chaîne. Aucun impact sur les performances également si le code est bien écrit. Voici un exemple avec 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);
}
1
Manish

Encore une autre option: https://github.com/stefanhaustein/expressionparser

J'ai implémenté ceci pour avoir une option simple mais flexible permettant à la fois:

Le TreeBuilder lié ci-dessus fait partie d'un package de démonstration CAS qui effectue une dérivation symbolique. Il existe également un exemple interpréteur BASIC et j'ai commencé à construire un interpréteur TypeScript qui l'utilise.

1
Stefan Haustein
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; }
   //.........
}
1
stone

Il est possible de convertir n'importe quelle chaîne d'expression en notation infixe en une notation postfixée en utilisant algorithme de triage de Djikstra . Le résultat de l'algorithme peut alors servir d'entrée à algorithme postfixe avec renvoie le résultat de l'expression.

J'ai écrit un article à ce sujet ici, avec une implémentation en Java

1
Emmanuel John

Une classe Java pouvant évaluer des expressions mathématiques:

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

    }

}
0
Efi G