我的PyParsing语法具有以下测试代码:

from pyparsing import Word, nums, alphas, delimitedList, Group, oneOf
from pprint import pprint

field = Word(alphas)("field")
operator = oneOf("= +")("operator")
string_value = Word(alphas)("string")
int_value = Word(nums).setParseAction(lambda t: int(t[0]))("int")
value = (string_value | int_value )("value")
expression = Group(field + operator + value)("expression")
grammar = Group(delimitedList(expression, delim="&&"))("expr_list")

def test(s):
    print "Parsing '{0}'".format(s)
    tokenized = grammar.parseString(s)
    for f in tokenized:
        e = f.expression
        pprint(dict(e.items()))

if __name__ == "__main__":
    test("foo=1")
    test("foo=1 && bar=2")
    test("foobar=2 && snakes=4")

输出是非常意外的-似乎我只在tokenized中得到了最后一个表达式:
Parsing 'foo=1'
{'field': 'foo', 'int': 1, 'operator': '=', 'value': 1}
Parsing 'foo=1 && bar=2'
{'field': 'bar', 'int': 2, 'operator': '=', 'value': 2}
Parsing 'foobar=2 && snakes=4'
{'field': 'snakes', 'int': 4, 'operator': '=', 'value': 4}

我该如何解决?

最佳答案

未经测试,但我认为您只需要更改:

expression = (field + operator + value)("expression")

至:
expression = Group(field + operator + value)("expression")

编辑:好的,另一个更改。您的迭代代码将查找多个名为“表达式”的项目。在以&&分隔的列表内有多个名为“表达式”的项目。不通过名称来引用它们,而是通过遍历“expr_list”内部的分组表达式来更简单地进行引用:
for f in tokenized['expr_list']:
    field = f['field']
    op = f['operator']
    value = f['value']
    print field, op, value

我通常在解析结果上使用dump方法,以查看数据如何分组和命名。如果我打印出tokenized.dump()我得到:
[[['foo', '=', 1], ['bar', '=', 2]]]
- expr_list: [['foo', '=', 1], ['bar', '=', 2]]
  - expression: ['bar', '=', 2]
    - field: bar
    - int: 2
    - operator: =
    - value: 2

我看到可以得到名为“expr_list”的值。我还看到有一个子级别的“表达式”,但是由于这些键在默认情况下像字典中一样是唯一的,因此最后解析的组只有一个值。但是我可以访问'expr_list'内部的多个组-如果查看第0个项目(使用print tokenized['expr_list'][0].dump()),则会得到:
['foo', '=', 1]
- field: foo
- int: 1
- operator: =
- value: 1

因此,我可以使用以下命令遍历“expr_list”中的组:
for f in tokenized['expr_list']:
    field = f['field']
    op = f['operator']
    value = f['value']
    print field, op, value

我会得到:
foo = 1
bar = 2

不必在语法的每个级别上放置结果名称-在这种情况下,我们通过遍历expr_list来获得表达式,甚至不使用expression。实际上,如果采用最外层语法表达式的Group,则也不需要'expr_list',只需迭代for f in tokenized:即可。

当尝试弄清返回的ParseResults的内容时,dump方法可能是最好的工具。

10-04 21:40