How to parse a mathematical expression given as a string and return a number? [duplicate]
Asked Answered
E

10

43

Is there a way in Java to get the result from this mathematical expression:

String code = "5+4*(7-15)";

In other hand what's the best way to parse an arithmetic expression?

Ezechiel answered 16/9, 2009 at 10:49 Comment(0)
L
36

You can pass it to a BeanShell bsh.Interpreter, something like this:

Interpreter interpreter = new Interpreter();
interpreter.eval("result = 5+4*(7-15)");
System.out.println(interpreter.get("result"));

You'll want to ensure the string you evaluate is from a trusted source and the usual precautions but otherwise it'll work straight off.

If you want to go a more complicated (but safer) approach you could use ANTLR (that I suspect has a math grammar as a starting point) and actually compile/interpret the statement yourself.

Lindsey answered 16/9, 2009 at 11:0 Comment(7)
Good idea, but problematic with untrusted input, as it would allow "script injection" (see my other comment).Sweetbread
@sleske: yeah, you'd certainly have to be careful with injection attacks if the string is user entered.Lindsey
Can also use built-in JavaScript (Rhino) interpreter now. Although seems more complex to get an eval. And still have a security risk...Mweru
@PhiLho: BeanShell was just something I used a few years ago, but I agree that something based on the javax.script API (I think Rhino is) would be better.Lindsey
+1 for beanshell, being part of the JREGramps
What would this return if the expression were "2/3"? Would it return 0 like Java does? You could stick a typecast in front, but then what about "(2/3)+(1/2)"?Metatherian
Trying to use beanshell... How can i guarantee that the result will always be in DOUBLE type?Type
H
31

i recently developed a expression parser and released it under the apache license. you can grab it at http://projects.congrace.de/exp4j/index.html

hope that helped

Harker answered 9/3, 2011 at 16:3 Comment(2)
Beautiful, incredibly simple to use and works great for my needs.Quieten
I won't be using this, because I actually need to parse one single expression throughout my application (from a configuration file), but if I had more and couldn't workaround the need, I'd certainly use this! I just had a look at this and it looks amazing (even custom functions are supported!). Great work!Cheryl
V
9

You can use the ScriptEngine class and evaluate it as a javascript string

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");        
Object result = engine.eval("5+4*(7-15)");

Indeed , yu should know that the result of the following instruction in javascript :

   eval('var aa=5+4*(7-15)')
   aa // -27

There may be a better way, but this one works.

Vexation answered 21/4, 2014 at 4:11 Comment(3)
Thanks, I prefer not to have to add dependencies when I don't really need to :DUnquiet
@Unquiet : it is not an external library, it is built-in javax.script.*Vexation
Understood, but since this expression is being read from an external file, JS engine evaluating arbitrary code is not an option.Unquiet
N
6

Recently I was using very mature math expression parser library, open source, giving the same API for JAVA and .NET. The library name is mXparser. mXparser provides basic functionalities (simple formulas parsing and calculation) and more advanced ones (i.e. user defined arguments, functions). Additionally it is worth to notice that mXparser has rich built-in math collection (meaning operators, unary / binary / variadic functions, iterated operators such as summation and product).

https://mathparser.org/

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

Please find below a few examples to have more clear view on the syntax.

Example 1 - simple formula

Expression e = new Expression("2+3");
double v = e.calculate();

Example 2 - built-in function

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

Example 3 - built-in constants

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

Example 4 - user defined arguments and constants

Argument x = new Argument("x = 5");
Constant a = new Constant("a = 2 + sin(3)");
Expression e = new Expression("a + x^2", x, a);
double v1 = e.calculate();
x.setArgumentValue(10);
double v2 = e.calculate();

Example 5 - user defined functions

Function f = new Function("f(x,y) = x^2 + cos(y)");
Expression e = new Expression("f(10,pi) - 3", f);
double v = e.calculate();

Example 6 - user defined recursion

Function factorial = new Function("fact(n) = if( n > 0; n*fact(n-1); 1)");
Expression e = new Expression("fact(10) - 10!", factorial);
double v = e.calculate();

Found recntly - in case you would like to try the syntax (and see the advanced use case) you can download the Scalar Calculator app that is powered by mXparser.

Best regards

LK

Necessity answered 31/3, 2016 at 19:22 Comment(0)
F
5

Probably not in as straight forward a manner as you are hoping!

But perhaps you could use a javax.script.ScriptEngine and treat the string as a ECMAScript expression, for example?

Take a look at: Scripting for the Java Platform.

Fortieth answered 16/9, 2009 at 10:57 Comment(3)
That is rather dangerous, as it would allow "script injection" (similar to SQL injection). Proceed with caution.Sweetbread
Good point. I suppose it depends on what the source of the expressions is.Fortieth
A regex could be used to strip all "non-math" characters from the input string. Would that secure the application from script injection? (Not planning on using this, but just came across it and it made me curious)Pes
T
4

There is no builtin way of doing that. But you can use one of the many many open source calculators available.

Treacy answered 16/9, 2009 at 10:55 Comment(0)
S
1

There is no direct support in the Java SDK for doing this.

You will either have to implement it yourself (possibly using a parser generator such as JavaCC), or use an existing library.

One option would be JEP (commercial), another JEval (free software).

Sweetbread answered 16/9, 2009 at 10:58 Comment(0)
I
0

There's an open-source tool called formula4j that does that job.

To take your example expression, it would be evaluated like this using formula4j:

Formula formula = new Formula("5+4*(7-15)");

Decimal answer = formula.getAnswer(); //-27

Ionia answered 15/2, 2013 at 0:43 Comment(1)
I updated the link. The formula4j tool is now open source.Ionia
S
0

You coul use that project

How to use:

double result = 0;
String code = "5+4*(7-15)";
try {
    Expr expr = Parser.parse(code);
    result = expr.value();
} catch (SyntaxException e) {
    e.printStackTrace();
}
System.out.println(String.format("Result: %.04f", result));
Schaffner answered 21/1, 2014 at 20:31 Comment(0)
B
-2
public static int calc(String string){
    int result=0; 
    String numbers="0123456789";
    String operations="+-/*";
    for (int i=0;i<string.length();i++){
        if (numbers.contains(string.charAt(i)+"")){
            result=result*10+(Integer.parseInt(string.charAt(i)+""));
            }
        else {
            if (string.charAt(i)=='+'){ result+=calc(string.substring(i+1));}
            if (string.charAt(i)=='-'){ result-=calc(string.substring(i+1));}
            if (string.charAt(i)=='*'){ result*=calc(string.substring(i+1));}
            if (string.charAt(i)=='/'){ try{result/=calc(string.substring(i+1));}
                catch (ArithmeticException e){
                    System.err.println("You cannot devide by Zero!");}
            }  
            break;
        }        
    }
    return result;
}
Bulkhead answered 19/12, 2014 at 10:51 Comment(5)
This would fail even with the simple example in the question.Macleod
Works well for me though.Bulkhead
Might work for you, but doesn't answer the question.Macleod
There´s always a better way of doing smth - there is no Best way for anything. Hope, you´ll find that useful.Bulkhead
this would fail at a+b*c , there is no priority between operators in this code ...Millerite

© 2022 - 2024 — McMap. All rights reserved.