控制String是否为数学表达式

时间:2015-09-16 08:53:27

标签: java parsing lexer mathematical-expressions

我正在寻找一种检查String是否是数学表达式的方法,即

  

x + y -sin(1)* 99k

我不想评估表达式,但要理解String是否以正确的方式编写。

有一些Java库可以做到吗?

更新 对不起,这不是一个等式,而只是一个表达式(没有' =')。 我考虑过一个可能的解决方案:

  1. 指定使用的变量
  2. 用' 1'
  3. 替换所有变量
  4. 使用JEval评估新字符串
  5. 如果程序引发异常,则表达式错误
  6. 您对此有何看法?

    由于

2 个答案:

答案 0 :(得分:4)

试试ANTLR。您可以编写如下语法:

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;

您应该更准确地定义语法,具体取决于允许的表达式和不允许的表达式。将其保存在文件Expr.g4中并执行antlr4 Expr.g4以获取ExprLexer.javaExprParser.java个文件。然后你可以用它们来检查一个句子是否是一个算术表达式:

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

}

最后测试:

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

您可以参考this问题。

答案 1 :(得分:1)

我的临时(和部分)解决方案。所有解决方案都很重,但Nashorn是内置的。 (要明确:我也使用ANTLR)

我在原始示例中遇到sin()函数问题,抛出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();
    }

我个人使用Groovy。 Raw Groovy eval有同样的问题groovy.lang.MissingMethodException: No signature of method: sin() is applicable ...

如果我更好地意识到这一点,我将捕获未知属性和未知方法....我不知道,如何在nashorn或JEval中捕获未知元素(但在语法上正确)