寻找一个表达式求值器

24
我正在寻找一个简单条件表达式的求值器。 这些表达式应包含变量(只读),字符串,数字和一些基本运算符。 例如,表达式可能如下所示:
${a} == "Peter" && ( ${b} == null || ${c} > 10 )

到目前为止,我实现了一个相当“神奇”的解析器,它返回了一个可以评估的AST,但我不相信我是第一个解决这个问题的人。

有哪些现有的代码可以代替我的解析器呢?


你想要评估哪种语言/语法?这是你自己编的吗?Java与此有什么关系? - Matt Ball
2
我猜楼主想要在JVM上运行的东西。 - Fred Foo
我们在一个项目中使用了JEP(http://www.singularsys.com/jep/),但出于性能原因,我真的想要一个小巧、适应性强的等效工具,可以为函数生成字节码。出于这个原因,我们放弃了JEP,并最终手动编写了大量Java类。也许有一个有创造力的人可以利用ANTLR和BCEL来实现这一点? - andersoj
@Matt Ball:这个例子是我现在使用的虚构语法。但当我找到一个符合我的要求的解析器,我可以采用它接受的任何语法。从语法上讲,我的主要目标是保持尽可能简约,因为我们可能会在单个集合中有许多(可达200个)这样的小条件。所以,易读性和性能是一项问题。 - Stroboskop
7个回答

16

你是否看过MVEL?他们提供了一个入门指南以及性能分析

这是他们简单示例之一:

// The compiled expression is serializable and can be cached for re-use.
CompiledExpression compiled = MVEL.compileExpression("x * y"); 

Map vars = new HashMap();
vars.put("x", new Integer(5));
vars.put("y", new Integer(10));

// Executes the compiled expression
Integer result = (Integer) MVEL.executeExpression(compiled, vars); 
assert result.intValue() == 50; 

回答自己的问题,MVEL似乎提供了一些支持字节码生成的功能。

其他可选方案,从上面的答案和我的经验中总结:


2
MVEL 项目文档已从 Codehaus 迁移。链接位置为 http://mvel.documentnode.com/。Github 位置为 https://github.com/mvel/mvel。 - Swapnil
但是MVEL对于像@{'11412Test'}或者@{'Test11412'}这样的字符串有问题,它无法解析上述文本并抛出错误。错误原因:[错误:无效的数字字面量:11412Test]。 - moh

8

7

1
现在已经太晚了,但那看起来就是我一直在寻找的东西。它专注于评估,但你有一个getAST方法可以返回表达式结构。 - Stroboskop

6

为什么不使用Rhino?它是JDK内置的JavaScript引擎。

它可以评估你想用JS编写的任何内容..在这里看看


事实上,我们已经在使用Rhino进行更大的自定义脚本。但是我不想给这些小表达式完整的脚本语言的能力。 - Stroboskop

3
这个简单的递归下降解析器将常数作为没有参数的命名函数进行评估。您可以查看此处获取更多信息。

4
如果我用科学代替魔法,我会走这条路。但现在我正在寻找一种已有的解决方案。 - Stroboskop

2

这是一个非常简单易用的替代方案,内置了许多用于字符串、日期和数字格式化的 Excel 函数。

该库还允许轻松添加自定义函数。在 git 页面上有很多例子。以下是使用变量的简单示例:

  ExpressionsEvaluator evalExpr = ExpressionsFactory.create("LEFT(City, 3)");
  Map<String, Object> variables = new HashMap<String, Object>();
  variables.put("City", "New York");
  assertEquals("New", evalExpr.eval(variables));

这个开箱即用的解决方案看起来非常有前途。但是我最终选择了Antlr并构建了我的自己的表达式语言。 - Stroboskop

0

这里是我开发的一个小型库,支持表达式求值(包括变量、字符串、布尔等)。

这是一个小例子:

String expression = "EXP(var)";
ExpressionEvaluator evaluator = new ExpressionEvaluator();
evaluator.putVariable(new Variable("var", VariableType.NUMBER, new BigDecimal(20)));

System.out.println("Value of exp(var) : " + evaluator.evaluate(expression).getValue());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接