2

I'm searching a way to check if a String is a mathematical expression as i.e.

x + y -sin(1) * 99k

i don't wanna evaluate the expression, but understand if the String is written in the right way.

There is some Java library for do that?

UPDATE: I'm sorry, is not an equation but only an expression (nothing '='). I have think about a possible solution:

  1. Specify the variables used
  2. replace all the variables with '1'
  3. evaluate the new String with JEval
  4. if the program raise an Exception, the expression is wrong

What you think about that?

Thanks

user229044
  • 232,980
  • 40
  • 330
  • 338
Tirrel
  • 778
  • 2
  • 7
  • 23
  • Does the expression need to be a correct one? If not, you could just check if it contains "=". – Oceans Sep 16 '15 at 08:55
  • not sure about library, but you can implement a BNF for it. but I'm sure since you don't really want to evaluate it there is an easier way – nafas Sep 16 '15 at 08:59
  • Duplicate of this http://stackoverflow.com/questions/2226863/whats-a-good-library-for-parsing-mathematical-expressions-in-java ? – Michael Sep 16 '15 at 09:06
  • @Michael Sort of, that question is about evaluation, which in theory should include parsing. – biziclop Sep 16 '15 at 09:28
  • Such half-ass solutions always have a weakness, e.g. `log (x - 1)` will fail in your case. Use a proper grammar, it's not hard. –  Sep 16 '15 at 10:09
  • Tell about validity is I think 90% of evaluating. Did You run in some envinronment i.e. servlet? Some have kind of expression evaluators "for free" – Jacek Cz Sep 16 '15 at 10:19

2 Answers2

4

Try ANTLR. You could write a grammar like:

grammar Expr;       

expr:   FuncitonName '(' expr ')'
    |   '-' expr
    |   '(' expr ')'
    |   expr '*' expr
    |   expr '+' expr
    |   expr '-' expr
    |   expr '/' expr
    |   Const
    |   Variable
    ;

FuncitonName : [a-z] + ; 
Variable : [a-zA-Z] + ;
Const : [0-9] +;

WS  :  [ \t\r\n\u000C]+ -> skip;

You should define the grammar more properly depending on which expression are allowed and which are not. Save it in the file Expr.g4 and execute antlr4 Expr.g4 to get your ExprLexer.java and ExprParser.java files. Then you could use them to check if a sentence is an arithmetic expression :

import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.BailErrorStrategy;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.misc.ParseCancellationException;

public static boolean isExpr(String exp) {

    ExprLexer lexer = new ExprLexer(new ANTLRInputStream(exp));
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    ExprParser parser = new ExprParser(tokens);

    parser.removeErrorListeners();
    parser.setErrorHandler(new BailErrorStrategy());

    try {
        parser.expr();
        return true;
    }  catch (ParseCancellationException e) {
        return false;
    }

}

and finally test:

System.out.println(isExpr("x + y -sin(1) * 99 * k")); //true
System.out.println(isExpr("x + y +")); //false

You could refer to this question.

Community
  • 1
  • 1
sve
  • 4,336
  • 1
  • 19
  • 30
  • ANTLR path is good (I use this tool), but require "a bit" programming and knowledge (probably not include 'sin' in grammar, but general term `function`) ... my proof of concept with evaluation is below – Jacek Cz Sep 16 '15 at 11:58
1

My ad-hoc (and partially) solution. All solutions are heavy-weight, but Nashorn is built-in. (to be clear: I use ANTLR too)

I have problem with sin() function in original example, throws javax.script.ScriptException: ReferenceError: "sin" is not defined in <eval>

    ScriptEngineManager scm = new ScriptEngineManager();
    ScriptEngine eng = scm.getEngineByName("nashorn");

    Integer k = 1;
    Integer x = 2;
    Integer y = 3;

    eng.put("k", k);
    eng.put("x", k);
    eng.put("y", k);

    Object ret = null;

    try {
        ret = eng.eval("x + y * 99 * k");
    } catch (ScriptException e) {
        e.printStackTrace();
    }

Personally I use Groovy. Raw Groovy eval has same problem groovy.lang.MissingMethodException: No signature of method: sin() is applicable ...

if I realized this better, I will trap unknown property and unknown method .... I don't know, how to trap unknown elements (but syntactically correct) in nashorn or JEval

Jacek Cz
  • 1,872
  • 1
  • 15
  • 22