L'évaluation d'une expression mathématique donné dans la forme d'une chaîne [fermé]

j'essaie d'écrire une routine Java pour évaluer des expressions mathématiques simples à partir des valeurs String comme:

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

je veux éviter beaucoup de déclarations if-then-else. Comment puis-je faire cela?

265
demandé sur Francesco Menzani 2010-08-06 13:53:30

24 réponses

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));
    } 
}
325
répondu RealHowTo 2017-04-07 15:04:05

j'ai écrit cette eval méthode d'expressions arithmétiques pour répondre à cette question. Il fait l'addition, la soustraction, la multiplication, la division, l'exponentiation (en utilisant le symbole ^ ), et quelques fonctions de base comme sqrt . Il supporte le groupement en utilisant ( ... ) , et il devient l'opérateur priorité et associativité règles correctes.

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 (qui est correcte)


L'analyseur est un descente récursive parser , donc utilise en interne séparée analyser les méthodes pour chaque niveau de priorité de l'opérateur dans sa grammaire. Je l'ai gardé court donc c'est facile à modifier, Mais voici quelques idées que vous pourriez vouloir l'étendre avec:

  • "1519340920 des Variables":

    le bit de l'analyseur qui lit les noms des fonctions peut facilement être modifié pour gérer les variables personnalisées aussi, en regardant les noms dans une table de variables passée à la méthode eval , comme un Map<String,Double> variables .

  • compilation et évaluation séparées:

    Que faire si, ayant ajouté le support pour les variables, vous voulait évaluer la même expression des millions de fois avec des variables changées, sans l'analyser à chaque fois? Il est possible de faire. Tout d'abord définir une interface à utiliser pour évaluer l'expression précompilée:

    @FunctionalInterface
    interface Expression {
        double eval();
    }
    

    maintenant changer toutes les méthodes qui retournent double s, donc à la place ils renvoient une instance de cette interface. La syntaxe lambda de Java 8 est parfaite 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;
            }
        }
    }
    

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

    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 changer l'évaluateur pour utiliser quelque chose de plus puissant comme BigDecimal , ou une classe qui met en œuvre nombres complexes, ou nombres rationnels (fractions). Vous pouvez même utiliser Object , permettant un certain mélange de types de données dans les expressions, tout comme un vrai langage de programmation. :)


tout le code dans cette réponse a libéré au Domaine public . Amusez-vous!

171
répondu Boann 2016-07-18 00:20:41

la bonne façon de résoudre ceci est avec un lexer et un parser . Vous pouvez écrire des versions simples de ceux-ci vous-même, ou ces pages ont également des liens vers Java lexers et parsers.

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

27
répondu Greg Hewgill 2010-08-06 10:15:17

ICI est une autre bibliothèque open source sur GitHub nommé EvalEx.

contrairement au moteur JavaScript, cette bibliothèque est axée sur l'évaluation des expressions mathématiques seulement. De plus, la Bibliothèque est extensible et supporte l'utilisation d'opérateurs booléens ainsi que des parenthèses.

15
répondu Tanvir 2013-09-04 00:41:27

vous pouvez également essayer le BeanShell interprète:

Interpreter interpreter = new Interpreter();
interpreter.eval("result = (7+21*6)/(32-27)");
System.out.println(interpreter.get("result"));
12
répondu marciowerner 2012-10-11 20:06:12

vous pouvez évaluer des expressions facilement si votre application Java accède déjà à une base de données, sans utiliser d'autres bocaux.

certaines bases de données exigent que vous utilisiez une table factice (par exemple, la table" dual "D'Oracle) et d'autres vous permettront d'évaluer des expressions sans" sélectionner " d'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 de l'utilisation D'un DB est que vous pouvez évaluer de nombreuses expressions en même temps. Aussi la plupart des DB vous permettront d'utiliser des expressions très complexes et auront également un certain nombre de fonctions supplémentaires qui peuvent être appelées si nécessaire.

cependant la performance peut souffrir si de nombreuses expressions simples doivent être évaluées individuellement, en particulier lorsque la base de données est située sur un serveur réseau.

ce qui suit résout le problème de performance dans une certaine mesure, en utilisant une base de données Sqlite en mémoire.

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 traiter plusieurs calculs en même temps.

ResultSet rs = stat.executeQuery( "select (1+10)/20.0 amount, (1+100)/20.0 amount2");
12
répondu DAB 2016-12-16 16:44:37

pour mon projet universitaire, je cherchais un analyseur / évaluateur supportant à la fois des formules de base et des équations plus compliquées (en particulier des opérateurs itérés). J'ai trouvé très belle bibliothèque open source pour JAVA et .NET appelé mXparser. Je vais donner quelques exemples pour donner un peu de sentiment sur la syntaxe, pour plus d'instructions s'il vous plaît visitez le site Web du projet (en particulier la section tutoriel).

http://mathparser.org /

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

http://mathparser.org/api /

et quelques exemples

1-Simple furmula

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

Best en ce qui concerne

10
répondu Leroy Kegan 2018-08-20 15:39:41

cet article pointe vers 3 approches différentes, une qui est JEXL de Apache et permet des scripts qui incluent des références à des objets java.

7
répondu Brad Parks 2012-07-02 20:32:43

une autre façon est D'utiliser le langage D'Expression de printemps ou SpEL qui fait beaucoup plus avec l'évaluation des expressions mathématiques donc peut-être un peu trop. Vous n'avez pas à utiliser Spring framework 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 plus concis SpEL exemples ici et le complète docs ici

6
répondu Faheem Sohail 2014-02-26 13:55:20

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
répondu Scorpion 2015-07-01 05:24:50

je pense que quelle que soit la façon dont vous le faites, il va impliquer beaucoup de déclarations conditionnelles. Mais pour les opérations simples comme dans vos exemples, vous pouvez le limiter à 4 si les déclarations 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é quand on veut faire face à des opérations multiples comme "4+5*6".

si vous essayez de construire une calculatrice alors je surgest passer chaque section du calcul séparément (chaque nombre ou opérateur), plutôt que comme une seule chaîne.

5
répondu BruteForce 2010-08-06 10:12:52

Il semble que JEP devrait faire le travail

5
répondu Bozho 2010-08-06 10:37:24

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

  1. pendant qu'il y a encore des jetons à lire,

    1.1 Obtenir le prochain jeton. 1.2 si le jeton est:

    1.2.1 un nombre: poussez-le sur la pile de valeurs.

    1.2.2 une variable: obtenir sa valeur, et pousser sur la pile de valeurs.

    1.2.3 une parenthèse à gauche: poussez-la sur le opérateur de pile.

    1.2.4 a 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. alors que la pile de l'opérateur n'est pas vide, 1 Pop l'opérateur de la pile de l'opérateur. 2 Pop la pile de valeur deux fois, obtenir deux opérandes. 3 Appliquer l'opérateur aux opérandes, dans le bon ordre. 4 poussez le résultat sur la pile de valeurs.

  3. à ce point la pile de l'opérateur doit être vide, et la valeur la pile doit avoir qu'une seule valeur, qui est le résultat final.

5
répondu Prashant Gautam 2015-09-18 12:39:58

vous pourriez jeter un oeil à la symja framework :

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

notez que des expressions 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
répondu Laurent Magnin 2015-10-29 13:40:05

essayez le code échantillon suivant en utilisant JDK1.Moteur Javascript 6 avec 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;
    }
 }
}
2
répondu Bruce 2016-09-24 08:11:22

cela complète en fait la réponse donnée par @Boann. Il a un léger bug qui fait que "-2 ^ 2" donne un résultat erroné de -4.0. Le problème est que le point de l'exponentiation est évaluée dans son. Il suffit de déplacer l'exponentiation vers le bloc de parseTerm(), et tout ira bien. Regardez ci-dessous, qui est la réponse de @Boann légèrement modifiée. 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();
}
2
répondu Romeo Sierra 2017-05-23 11:47:18
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));
}

}

2
répondu chejaras 2018-02-15 08:18:43

Que Diriez-vous de quelque chose comme ceci:

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
répondu konxie 2012-10-17 20:06:38

il est possible de convertir n'importe quelle chaîne d'expression dans la notation infix en une notation postfix en utilisant algorithme de djikstra shunting-yard . Le résultat de l'algorithme peut alors servir comme entrée pour le postfix "algorithme 151920920" avec renvoie le résultat de l'expression.

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

1
répondu Emmanuel John 2015-07-06 00:15:15

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

MVEL fait l'évaluation d'exécution des expressions, nous pouvons écrire un code java dans String pour l'obtenir évalué dans ce.

    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);
1
répondu Saravana 2015-10-19 12:37:25
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
répondu stone 2016-03-29 16:21:01

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

j'ai mis en œuvre ceci pour avoir une option simple mais flexible pour permettre à la fois:

Le "treebuilder" lié ci-dessus fait partie d'un CAS démo qui n'symbolique de dérivation. Il y a aussi un exemple interpréteur de base et j'ai commencé à construire un interpréteur de type en l'utilisant.

1
répondu Stefan Haustein 2016-04-17 01:00:30

une bibliothèque externe comme RHINO ou NASHORN peut être utilisée pour exécuter javascript. Et javascript peut évaluer la formule simple sans parquer la chaîne. Aucun impact sur la performance si le code est bien écrit. Voici un exemple avec le 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
répondu Manish 2017-10-20 03:50:53

une classe Java qui peut é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
répondu Efi G 2017-08-03 01:06:45