在Groovy表达式中使用文字运算符(例如“和”、“或”)吗?
我当前的工作项目允许在特定的上下文中对用户提供的表达式进行评估,作为扩展和影响工作流的一种方式。这些表达式与通常的逻辑表达式f。为了让非程序员更容易接受,我想让他们选择使用文字运算符(例如and、or、not代替&、|、!) 简单的搜索和替换是不够的,因为数据可能包含引号中的单词,构建解析器虽然可行,但可能不是最优雅和有效的解决方案 要明确问题:Groovy中是否有允许用户编写代码的方法在Groovy表达式中使用文字运算符(例如“和”、“或”)吗?,groovy,dsl,Groovy,Dsl,我当前的工作项目允许在特定的上下文中对用户提供的表达式进行评估,作为扩展和影响工作流的一种方式。这些表达式与通常的逻辑表达式f。为了让非程序员更容易接受,我想让他们选择使用文字运算符(例如and、or、not代替&、|、!) 简单的搜索和替换是不够的,因为数据可能包含引号中的单词,构建解析器虽然可行,但可能不是最优雅和有效的解决方案 要明确问题:Groovy中是否有允许用户编写代码的方法 x > 10 and y = 20 or not z 但让Groovy对其进行评估,就像: x &
x > 10 and y = 20 or not z
但让Groovy对其进行评估,就像:
x > 10 && y == 20 || !z
谢谢。将和()。如果您提供了如下方法
Boolean not(Boolean b) {return !b}
你可以这样写
(x > 10).and(y == 20).or(not(4 == 1))
不过,我不确定这是否特别容易编写。如果您可以将
和=
这样的操作符分别替换为gt
和eq
这样的facelet,我认为您的情况可能是可行的,尽管这需要很多努力:
x gt 10 and y eq 20 or not z
决心:
x(gt).10(and).y(eq).20(or).not(z)
这将是地狱般的解析
@Brian Henry建议的方法是最简单的方法,尽管不便于用户使用,因为它需要括号和圆点
好的,考虑到我们可以交换运算符,您可以尝试截取整数。调用来启动表达式。将脚本中缺少的属性解析为操作可以解决新的关键字问题。然后可以构建表达式并将其保存到列表中,并在脚本末尾执行它们。它还没有完成,但我带来了这个:
// the operators that can be used in the script
enum Operation { eq, and, gt, not }
// every unresolved variable here will try to be resolved as an Operation
def propertyMissing(String property) { Operation.find { it.name() == property} }
// a class to contain what should be executed in the end of the script
@groovy.transform.ToString
class Instruction { def left; Operation operation; def right }
// a class to handle the next allowed tokens
class Expression {
Closure handler; Instruction instruction
def methodMissing(String method, args) {
println "method=$method, args=$args"
handler method, args
}
}
// a list to contain the instructions that will need to be parsed
def instructions = []
// the start of the whole mess: an integer will get this called
Integer.metaClass {
call = { Operation op ->
instruction = new Instruction(operation: op, left: delegate)
instructions << instruction
new Expression(
instruction: instruction,
handler:{ String method, args ->
instruction.right = method.toInteger()
println instructions
this
})
}
}
x = 12
y = 19
z = false
x gt 10 and y eq 20 or not z
不确定它是否值得。Groovy支持的最新版本,因此确实可以编写以下内容:
compute x > 10 and y == 20 or not(z)
这里的“compute”一词是任意的,但不能省略,因为它是命令链中的第一个“动词”。接下来的每件事都在动词和名词之间交替:
compute x > 10 and y == 20 or not(z)
───┬─── ──┬─── ─┬─ ───┬─── ─┬─ ──┬───
verb noun verb noun verb noun
命令链的编译方式如下:
verb(noun).verb(noun).verb(noun)...
因此,将上述示例编译为:
compute(x > 10).and(y == 20).or(not(z))
有很多方法可以实现这一点。这里只是一个快速而肮脏的概念证明,它没有实现运算符优先级,除此之外:
class Compute {
private value
Compute(boolean v) { value = v }
def or (boolean w) { value = value || w; this }
def and(boolean w) { value = value && w; this }
String toString() { value }
}
def compute(v) { new Compute(v) }
def not(boolean v) { !v }
您可以单独使用命令链(作为顶级语句)或在赋值运算符(局部变量或属性赋值)的右侧使用,但不能在其他表达式中使用。我认为您需要编写自己的解析器,您的意思是&
和
?或者你真的是指按位运算符?@WillP My bad,我指的是逻辑运算符。我修正了这个问题。谢谢,但事实上,这一点都不容易。谢谢威尔,对于这个特殊的案例来说,这确实是太多的工作了
class Compute {
private value
Compute(boolean v) { value = v }
def or (boolean w) { value = value || w; this }
def and(boolean w) { value = value && w; this }
String toString() { value }
}
def compute(v) { new Compute(v) }
def not(boolean v) { !v }