为什么pyparsing删除命名结果?

时间:2012-11-05 21:59:04

标签: python pyparsing

给出以下最小的工作示例:

from pyparsing import *
latex_h  = QuotedString("$")('latex')
reg_text = Word(alphas)('text')
grammar  = OneOrMore( latex_h | reg_text )('line')

sol = grammar.parseString('''dog $x^2$ cat''')
print sol.dump()

我希望输出看起来像:

['dog', 'x^2', 'cat']
- line: ['dog', 'x^2', 'cat']
  - text: dog
  - latex: x^2
  - text: cat

但我得到了:

['dog', 'x^2', 'cat']
- latex: x^2
- line: ['dog', 'x^2', 'cat']
  - latex: x^2
  - text: cat
- text: cat

我不明白为什么在解析树中dog落后了?另外,为什么text, latex 的两个元素line之外?

1 个答案:

答案 0 :(得分:3)

正如Russell Borogove所说,在相同的解析级别上,命名结果必须是唯一的。你不能拥有两个或多个相同类型的命名元素的“行”(例如两个“text”或两个“latex”),因为它们都将在底层字典中使用相同的键。关于最新PyParsing中的listAllMatches解决方案,我会听从Paul McGuire的看法,因为他写了这篇文章并且所有内容:)

您也可以通过将解析操作附加到“latex_h”或“reg_text”来解决此问题,但是如果“latex_h”元素需要知道任何兄弟“reg_text”元素,这将无济于事。在这种情况下,您可能需要进一步分解语法,或使用基于树的方法进行解析(从最低元素到根,通过解析操作和/或迭代结果列表)而不是基于字典的方法。

重要的是要注意,解析树后面留下了“狗”。它被正确解析,只是解析后的结果没有被分配到字典。您可以像这样访问解析后的值:sol.line[0]

至于为什么'latex'和'cat'出现在'line'之外,你需要将OneOrMore定义放在Group()中。

这是一个示例,它在解析时将reg_text元素应用于解析(而不是解析任何父元素,如grammar)。它没有解决您遇到的“命名结果”问题,但是如果没有使用解析器尝试实现的内容,我无法提出解决方案。

from pyparsing import *
latex_h  = QuotedString("$")('latex')
reg_text = Word(alphas)('text')
grammar  = Group(OneOrMore( latex_h | reg_text ))('line')

def parse_reg_text(s, loc, toks):
    if toks.text == 'dog':
        return "atomic " + toks.text
    else:
        return "ninja " + toks.text

reg_text.setParseAction(parse_reg_text)

sol = grammar.parseString('''dog $x^2$ cat $y^3$''')
print sol.dump()

这给出了以下输出:

[['atomic dog', 'x^2', 'ninja cat', 'y^3']]
- line: ['atomic dog', 'x^2', 'ninja cat', 'y^3']
  - latex: y^3
  - text: ninja cat