views:

313

answers:

11

Is there an easy way to take a String such as "5*4" and return 20?

+3  A: 

You probably looking for something like JbcParser - Math Parser for Java.

Artem Barger
Although perhaps worth pointing out that it's not free (in either sense).
Simon Nickerson
Seriously Artem? "This" is a horrible link descriptor and rolling back my edit is totally ignorant.
animuson
+2  A: 

I don't know which are the best out there but there are "mathematical expressions evaluator" packages.

check out Java Math Expression Evaluator (one file source code included)

Example use from site:

java -cp meval.jar com.primalworld.math.MathEvaluator -cos(0)*(1+2)
java -cp meval.jar com.primalworld.math.MathEvaluator .05*200+3.01

Bakkal
Since I'm developing for Version 5, this one works the best for me.
George
+1  A: 

You are best off using a library for this. Janino has the ability to evaluate arbitrary Java expressions like the ones you specify, and more besides.

Check out the ExpressionEvaluator example.

Simon Nickerson
A: 

You could try parsing it yourself by using Integer.parseInt() and using a switch() statement to find the operators.

You could also try using javax.script.ScriptEngine; for more information see http://forums.sun.com/thread.jspa?threadID=5144807.

masseyc
If all the expressions are two-numbers-and-one-operator, maybe. In the real world, what result do you expect from "5+4*3" - I would expect 17 rather than 27, meaning precedence is important. Precedence parsing isn't that hard, but it's certainly non-trivial. I'm with the "use a library" answers.
Steve314
+2  A: 

More details about expression evaluation can be found at:

Algorithms in Java, Volume 1, Parts 1-4

Pardeep
A: 
Klinger
+4  A: 

The most simple way would be to use the Rhino JavaScript engine available with the JRE 6 standard API.

Edit: as per the comments, if the strings are user-supplied, this could be a potential security hole. Be sure to filter out everything except digits, braces and mathematical operators.

Michael Borgwardt
Yes ... but a javascript engine does a whole lot more besides. If you exposed the Rhino evaluator in some contexts, you would potentially introduce ... ahem ... security issues.
Stephen C
This kind of thing always reminds me of SQL code injection exploits. If those strings come from outside the program (user, file, socket...), in order to be sure they aren't potential security risks you may need to parse them anyway. Well, OK, not quite - you can probably get away with a regular-expression check as you only care about the set of legal tokens. And Javascript doesn't have standard file ops etc, so you may be safe anyway. Still - it makes me nervous.
Steve314
Hmmm - I really should refresh before commenting. Oh well.
Steve314
+1  A: 

I have googled a bit and found that one here. Its not exactly what you need, but maybe it helps depsite of that.

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class ScriptDemo {

    public static void main(String[] args) {

        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("js");

        engine.put("a", 1);
        engine.put("b", 2);

        try {
            String expression = "(a + b) > 2";
            Object result = engine.eval(expression);
            System.out.println(expression+" ? "+result);
        } catch(ScriptException se) {
            se.printStackTrace();
        }
    }
}
InsertNickHere
+1  A: 

You can also use BeanShell.
It is actually more a Java source interpreter, but recently I used it to evaluate some expressions containing variables (only the eval method is using BeanShell, the rest is for preparing the output):

import bsh.EvalError;
import bsh.Interpreter;

public class EVAL {

    private static final String FORMAT = "%-5s | %-5s | %-5s | %s%n";

    public static void main(String[] args) {
        tabela("((a && b)||c)");
        tabela("a ? (b || c) : (b && c)");
        tabela("(a?1:0) + (b?1:0) + (c?1:0) >= 2");
    }

    private static void tabela(String expressao) {
        System.out.printf(FORMAT, "  a  ", "  b  ", "  c  ", expressao);
        System.out.printf(FORMAT, "-----", "-----", "-----", expressao.replaceAll(".", "-"));
        try {
            for (int i = 0; i < 8; i++) {
                boolean a = (i & (1<<2)) != 0;
                boolean b = (i & (1<<1)) != 0;
                boolean c = (i & (1<<0)) != 0;
                boolean r = eval(expressao, a, b, c);
                System.out.printf(FORMAT, a, b, c, r);
            }
        } catch (EvalError ex) {
            ex.printStackTrace();
        }
        System.out.println();
        System.out.println();
    }

    private static boolean eval(String expressao, boolean a, boolean b, boolean c) throws EvalError {
        Interpreter inter = new Interpreter();
        inter.set("a", a);
        inter.set("b", b);
        inter.set("c", c);
        Object resultado = inter.eval(expressao);
        return (Boolean) resultado;
    }
}

results:

  a   |   b   |   c   | ((a && b)||c)
----- | ----- | ----- | -------------
false | false | false | false
false | false | true  | true
false | true  | false | false
false | true  | true  | true
true  | false | false | false
true  | false | true  | true
true  | true  | false | true
true  | true  | true  | true


  a   |   b   |   c   | a ? (b || c) : (b && c)
----- | ----- | ----- | -----------------------
false | false | false | false
false | false | true  | false
false | true  | false | false
false | true  | true  | true
true  | false | false | false
true  | false | true  | true
true  | true  | false | true
true  | true  | true  | true


  a   |   b   |   c   | (a?1:0) + (b?1:0) + (c?1:0) >= 2
----- | ----- | ----- | --------------------------------
false | false | false | false
false | false | true  | false
false | true  | false | false
false | true  | true  | true
true  | false | false | false
true  | false | true  | true
true  | true  | false | true
true  | true  | true  | true
Carlos Heuberger
+1  A: 

I have used JEval in the past and have found it quite easy and intuitive. Here is a code snippet:

import net.sourceforge.jeval.EvaluationException;
import net.sourceforge.jeval.Evaluator;

public class Main {
    public static void main(String[] args) {
        try {
            System.out.println(new Evaluator().evaluate("5+4*3"));
        }
        catch (EvaluationException e) {
            e.printStackTrace();
        }
    }
}
dogbane
+1  A: 

Sounds like you should check out JEXL (Java Expression Language)

It is very easy to use; for example, the solution to your problem is:

  public static void main(String[] args) {
    long a = 5;
    long b = 4;
    String theExpression = "a * b";
    JexlEngine jexl = new JexlEngine();
    Expression e = jexl.createExpression(theExpression);
    JexlContext context = new MapContext();
    context.set("a", a);
    context.set("b", b);
    Long result = (Long) e.evaluate(context);
    System.out.println("The answer : " + result);
  }

Alternatively you could use the following if the string is read in directly:

 public static void main(String[] args) {
   JexlEngine jexl = new JexlEngine();
   Expression e = jexl.createExpression("5 * 4");
   Integer result = (Integer) e.evaluate(null);
   System.out.println("The answer : " + result);
 }
Syntax