我遇到了解析已解析结果的问题。我有一个解析表达式的语法。在语法中的每个规则中都有setResultName()函数,因此我可以轻松地操作解析后的结果。但是当使用dump()函数来查看结果的组织方式时,它不会显示所有已解析的结果。但是,当使用asXML()函数时,所有结果都存在并按我想要的结构。
这是语法:
# Rule for any alphanumeric word
identifier = Word(alphas, alphas + nums)
# Rule for "e" in floating point numbers
e = CaselessLiteral('E')
# Rule for booleans
boolean = (Keyword('True')
| Keyword('False')
).setParseAction(lambda tokens: bool(tokens[0])).setResultsName("boolean")
# Rule for integer numbers
integer = Word(nums).setParseAction(lambda tokens: int(tokens[0]))
# Rule for factor operator
factor_operator = (Literal('*')
| Literal('/')
| Literal('%')
).setResultsName("operator")
# Rule for term operator
term_operator = (Literal('+')
| Literal('-')
).setResultsName("operator")
# Rule for double numbers
double = Combine(integer +
Optional(Literal('.') + Optional(integer)) +
Optional(e + Optional(term_operator) + integer)
).setParseAction(lambda tokens: float(tokens[0])).setResultsName("double")
# Forwarding expression rule
expression = Forward()
# Rule define type of factor
factor = Group((
Literal('(').suppress() +
expression.setResultsName("expression") +
Literal(')').suppress())
| double
| boolean
).setResultsName("factor")
# Rule for factors
factors = Group(ZeroOrMore(factor_operator + factor)).setResultsName("factors")
# Rule for term
term = Forward()
term << Group(factor + delimitedList(factors)).setResultsName("term")
# Rule for terms
terms = Group(ZeroOrMore(term_operator + term)).setResultsName("terms")
# Rule for expression
expression << Group(Optional(term_operator) + term + delimitedList(terms)
).setResultsName("expression")
return expression
这是我要解析的表达式:
&#34;(2 * 3)+ 20/5 - 1&#34;
这是dump()的输出:
[[[[[[[2.0], ['*', [3.0]]], []]], []], ['+', [[20.0], ['/', [5.0]]], '-', [[1.0], []]]]]
- expression: [[[[[[2.0], ['*', [3.0]]], []]], []], ['+', [[20.0], ['/', [5.0]]], '-', [[1.0], []]]]
- term: [[[[[2.0], ['*', [3.0]]], []]], []]
- factor: [[[[2.0], ['*', [3.0]]], []]]
- expression: [[[2.0], ['*', [3.0]]], []]
- term: [[2.0], ['*', [3.0]]]
- factor: [2.0]
- double: 2.0
- factors: ['*', [3.0]]
- factor: [3.0]
- double: 3.0
- operator: *
- terms: []
- factors: []
- terms: ['+', [[20.0], ['/', [5.0]]], '-', [[1.0], []]]
- operator: -
- term: [[1.0], []]
- factor: [1.0]
- double: 1.0
- factors: []
asXML()的输出:
<expression>
<expression>
<term>
<factor>
<double>2.0</double>
</factor>
<factors>
<operator>*</operator>
<factor>
<double>3.0</double>
</factor>
</factors>
</term>
<terms>
<operator>-</operator>
<term>
<factor>
<double>20.0</double>
</factor>
<factors>
<operator>/</operator>
<factor>
<double>5.0</double>
</factor>
</factors>
</term>
<operator>+</operator>
<term>
<factor>
<double>1.0</double>
</factor>
<factors>
</factors>
</term>
</terms>
</expression>
</expression>
问题出在带括号的嵌套表达式后的术语标记上。在xml中,它显示其中的所有术语(即&#39; +&#39;,&#39; 20.0 / 5.0&#39;,&#39; - &#39;,&#39; 1.0&#39;),它应该是运算符和术语列表。使用dump()函数时,它只显示最后一个运算符和术语(即&#39; - &#39;,&#39; 1.0&#39;)。 任何人都可以帮我理解这个吗?有什么东西我错过了吗?对于我错过的任何事情都很抱歉。
答案 0 :(得分:2)
如果dump()
和asXML()
之间存在差异,我更有可能将其视为asXML()
中的错误。这种方法被迫做了一些&#34;猜测&#34;关于什么是想要的,我可以很容易地看到它在某些情况下猜错了。
pyparsing的默认行为是将所有已解析的标记作为平面字符串列表返回。无论如何构建解析器,它都会执行此操作。这是
(A + B + C).parseString
AA = A + B
(AA + C).parseString
and
DD = B + C
(A + DD).parseString
都返回相同的东西。
让我们看一个简单的语法,一个名称/年龄对的倍数:
test = "Bob 10 Sue 12 Henry 7"
这是我们的解析器:
name = Word(alphas)
integer = Word(nums)
parser = OneOrMore(name + integer)
# or you can use the new multiplication syntax
parser = (name + integer) * (1,)
使用给定的示例文本和上面的解析器,这将是:
['Bob', '10', 'Sue', '12', 'Henry', '7']
现在这不是一件难以走过的事,一次阅读两件物品。但如果有其他可选字段,那么事情会变得棘手。因此,告诉pyparsing每个人的姓名和年龄应该组合在一起要容易得多。
parser = OneOrMore(Group(name + integer))
现在我们为每个人获得一个子列表,如果可能有其他选项,则无法猜测。
[['Bob', '10'], ['Sue', '12'], ['Henry', '7']]
如果您将结果名称添加到原始未分组解析器中,我们会看到这一点(我使用&#34;新&#34;可调用语法而不是罗嗦&分散注意力&#34; setResultsName&#34;调用格式):
parser = OneOrMore(name("name") + integer("age"))
result = parser.parseString(test)
了解我们现在所知道的关于未分组结果的内容,如果我们要求result.name
,我们应该得到哪个名字?
如果您的情况中有多个表达式共享相同的结果名称,那么您有3个选项:
只保留解析的最后一个(默认情况,这就是你所看到的)
使用Group类添加分组,以便将多个共享结果分成不同的子结构
将listAllItems=True
参数添加到setResultsName()
parser = OneOrMore(name.setResultsName(&#34; name&#34;,listAllItems = True)+ integer.setResultsName(&#34; age&#34;,listAllItems = True))
或者如果使用缩写的可调用格式,请添加&#39; *&#39;到结果名称的末尾:
parser = OneOrMore(名称(&#34;名称*&#34;)+整数(&#34;年龄*&#34;))
现在result.name将为您提供列表中的所有已解析名称,result.age将为您提供相应的年龄。但对于这样的数据,我更愿意将数据解析成组。
parser = OneOrMore(Group(name("name") + integer("age")))
如果您希望asXML()
使用标记#34; person&#34;标记每个群组,请将该名称添加到群组中,并附上&#39; *&#39;抓住他们。
parser = OneOrMore(Group(name("name") + integer("age"))("person*")
(这已经是一个冗长的答案,所以我遗漏了这些测试中的dump()和asXML()输出 - 留给OP和未来读者的练习。)