运行时的动态表达式求值器

4

我有一个应用程序,我想使用某种表达式解析器来定制它。

我希望能够在不重新编译代码的情况下更改应用程序的某些部分。

我考虑使用Groovy表达式。

例如,我有一个功能可以通过提供表达式来启用/禁用:

在这种情况下,此功能将被启用。

Example 1:
EXPRESSION : status = part-time || status = hourly
INPUT: status = part-time

在这种情况下,此功能将被禁用。
Example 2:
EXPRESSION : status = part-time || status = hourly
INPUT: status = permanent

用户需要输入一个表达式和一个输入。表达式应该求值为布尔表达式。

他们还可以更改表达式,程序将通过一些评估来捕获这个变化。 顺便说一下,这些表达式已经有文档说明,并且我向我的应用程序用户公开了它们。

Example 3:
EXPRESSION : salary > 10000
INPUT: salary = 7000

我之前见过一个程序可以做到这一点,他们说在幕后使用了Groovy。 但是我无法理解这个概念。

有人能给我一个想法吗?


你具体想做什么?你试图解决的问题是什么?如果只是启用或禁用一个功能,布尔变量可以为您完成这项工作,因此很难看出问题在哪里。 - nbrooks
嗨,伙计,正如我所提到的,我希望我的程序能够通过传递表达式来改变其行为。这样就不需要重新编译代码了。这个想法是任何人都可以扩展我的代码,而不必改变底层程序,只需使用公开的表达式即可。 - Mark Estrada
我不理解为什么我的问题被投了关闭票。我正在寻求指导,因此无法发布任何代码。为什么我会收到关闭票?这毫无意义。 - Mark Estrada
2个回答

3

使用evaluate的替代方法。您的变量在绑定中定义,evaluate包含表达式:

// setup binding
def emp = [status:'permanent', name:'Hugo']
def binding = new Binding()
binding.status = 'permanent'
binding.status2 = 'part-time'
binding.salary = 7000
binding.employee = emp
println binding.variables

// evaluate the script
def ret = new GroovyShell(binding).evaluate("status == 'part-time' || status == 'hourly'")
println ret

ret = new GroovyShell(binding).evaluate("status2 == 'part-time' || status2 == 'hourly'")
println ret

ret = new GroovyShell(binding).evaluate("salary > 10000")
println ret

ret = new GroovyShell(binding).evaluate("employee.status == 'permanent' || employee.status == 'hourly'")
println ret

返回值
[status:permanent, status2:part-time, salary:7000, employee:[status:permanent, name:Hugo]]
false
true
false
true

哦,原来是这样...你如何解析那些带有点(.)的表达式呢?例如,如果不是status,而是employee.status呢?我在评估Groovy时遇到了编译问题。 - Mark Estrada
@MarkEstrada添加了一个使用哈希映射的绑定示例。 - Marmite Bomber

2

常规的Groovy脚本调用:

import groovy.lang.Binding;
import groovy.lang.Script;
import groovy.lang.GroovyShell;

Binding binding = new Binding();
binding.setProperty("status", "part-time");
GroovyShell shell = new GroovyShell(binding);
Script script = shell.parse(" status == 'part-time' || status == 'hourly' ");
Object result = script.run();

运行后,绑定将填充变量的新值。
您可以缓存已解析的脚本(或已解析的脚本类),因为解析/编译是昂贵的过程。
作为替代方案-最简单的脚本评估:
Object result = groovy.util.Eval.me("status", "part-time", 
    " status == 'part-time' || status == 'hourly' ");

哦,原来是这样啊...你怎么解析那些带点的表达式呢?比如说不是 status,而是 employee.status?我在 Groovy 中评估时遇到编译问题。 - Mark Estrada
你可以将Groovy视为动态编译的Java。只需将“employee”变量传递到脚本中,脚本就能够访问此对象的所有属性和方法。 - daggett
但是员工不是一个对象..它只是一个标签或其他东西... 我收到了groovy.lang.MissingPropertyException: Script1类中没有名为employee的属性。 - Mark Estrada
有没有一种方法可以跳过点(dot)操作符... 表达式可能是label.name或sample.data? - Mark Estrada
在我提供的代码中,binding.setProperty("status", "part-time") 这一行定义了一个名为 status 的变量,它引用了一个值为 part-time 的 Java String 对象。在 Groovy 脚本中,您可以像这样访问 Java String 方法 toUpperCase()status.toUpperCase(),这个表达式将返回 PART-TIME - daggett

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