我正在尝试使用以下 pyparsing 代码解析一个简单的过滤器列表:
filters = pp.Forward()
filters <<= pp.delimited_list(
pp.Group(
(
NOT # not literal
+ LBRKT # [
+ pp.Group(filters)
+ RBRKT # ]
)
| (
(AND | OR) # and/or literal
+ LBRKT
+ pp.Group(filters)
+ RBRKT
)
| filter_li # parses field[1,2] / field[gt:20,lt:30]
| filter_op # parses field:in:[1,2] / field:eq:10
| filter_eq # parses field:10
)
)
这正确解析了以下内容
field[lt:10],field[gt:10] -> [['field', [['lt', 10]]], ['field', [['gt', 10]]]]
field1:gt:0,field1:lt:10,field2:gt:0,field2:lt:10 -> [['field1', 'gt', 0], ['field1', 'lt', 10], ['field2', 'gt', 0], ['field2', 'lt', 10]]
field1[gt:0,lt:10],field2[gt:0,lt:10] -> [['field1', [['gt', 0], ['lt', 10]]], ['field2', [['gt', 0], ['lt', 10]]]]
and[field1[gt:0,lt:10],field2[gt:0,lt:10]] -> [['and', [['field1', [['gt', 0], ['lt', 10]]], ['field2', [['gt', 0], ['lt', 10]]]]]]
field:eq:10,field2:eq:20 -> [['field', 'eq', 10], ['field2', 'eq', 20]]
and[field:eq:10,field2:eq:20] -> [['and', [['field', 'eq', 10], ['field2', 'eq', 20]]]]
or[field:lt:0,field2:gt:10] -> [['or', [['field', 'lt', 0], ['field2', 'gt', 10]]]]
not[field:10,field2:20] -> [['not', [['field', 10], ['field2', 20]]]]
not[and[field:10,field2:20]] -> [['not', [['and', [['field', 10], ['field2', 20]]]]]]
and[field:eq:10,field2:eq:20,or[field3:eq:10,field4:eq:20]] -> [['and', [['field', 'eq', 10], ['field2', 'eq', 20], ['or', [['field3', 'eq', 10], ['field4', 'eq', 20]]]]]]
or[field:10,field2:20],not[field3:10,field:10] -> [['or', [['field', 10], ['field2', 20]]], ['not', [['field3', 10], ['field', 10]]]]
or[field1:10,field2:20],field3:30 -> [['or', [['field1', 10], ['field2', 20]]], ['field3', 30]]
not[field1:10],and[field2:20,field3[1,2],field4[gt:10,lt:20],or[field5:10,field6:20]] -> [['not', [['field1', 10]]], ['and', [['field2', 20], ['field3', [1, 2]], ['field4', [['gt', 10], ['lt', 20]]], ['or', [['field5', 10], ['field6', 20]]]]]]
但我想失败
and[field:10] -> [['and', [['field', 10]]]]
or[field:10] -> [['or', [['field', 10]]]]
这是因为和/或需要多个过滤器。
如何更新代码以验证最小值?
我尝试在和/或部分中使用 delimited_list,但我认为外部 delimited_list 总是优先,然后 min=2 不起作用。
您可以使用 add_condition():
在语法中添加最小长度谓词(
(AND | OR) # and/or literal
+ LBRKT
+ pp.Group(filters).add_condition(lambda toks: len(toks[0]) >= 2)
+ RBRKT
)
(此外,如果您的递归语法存在性能问题,请查看调用 enable_packrat()。)