给出以下最小的工作示例:
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
之外?
答案 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