如何在 pyparsing 中要求递归定义中的最小项?

问题描述 投票:0回答:1

我正在尝试使用以下 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 不起作用。

python python-3.x pyparsing
1个回答
0
投票

您可以使用 add_condition():

在语法中添加最小长度谓词
(
    (AND | OR) # and/or literal
    + LBRKT
    + pp.Group(filters).add_condition(lambda toks: len(toks[0]) >= 2)
    + RBRKT
)

(此外,如果您的递归语法存在性能问题,请查看调用 enable_packrat()。)

© www.soinside.com 2019 - 2024. All rights reserved.