Pyparsing newbie setParseAction修改令牌

时间:2012-12-01 13:37:18

标签: python pyparsing

我是Pyparsing的新手(也是Python的新手)。我试图将我的问题简化为最简单的形式,以说明出现了什么问题(我可能根本不需要Pyparsing!)

假设我有一个由字母和数字组成的字符串,例如“b7 z4 a2 d e c3”。总有一封信,但号码是可选的。我想将它解析为它的各个元素,然后处理它们,但是如果有一个没有数字的裸字,那么更改它以便它具有“默认”数字1之后将会很方便。然后我可以以一致的方式处理每个元素。我以为我可以使用setparseAction执行此操作,如下所示:

from pyparsing import *
teststring = "a2 b5 c9 d e z"
expected_letter = Word("ABCDEFGabcdefgzZxy", exact=1)
expected_number = Word(nums)
letter_and_number = expected_letter + expected_number
bare_letter = expected_letter
bare_letter.setParseAction( lambda s,l,t:  t.append("1") )
elements =  letter_and_number | bare_letter
line = OneOrMore(elements)
print line.parseString(teststring)

不幸的是,t.append()没有做我期望的事情,即在解析的令牌列表中添加“1”。相反,我得到一个错误:TypeError:'str'对象不可调用。

我可能只是真的很厚,在这里,但你们中的一位专家请让我直截了当。

由于

史蒂夫

1 个答案:

答案 0 :(得分:4)

获得pyparsing的基本概念之一是它不仅仅用于字符串列表,而是将解析后的部分组装成ParseResults对象。 ParseResults是一个在pyparsing中定义的丰富数据类型,可以作为列表访问,如果有从具有已定义结果名称的ParserElement解析的标记,则可以作为dict或对象访问。

然而,虽然ParseResults的设计考虑到了易于访问,但它的更新方式受到限制。在pyparsing内部,匹配的每个表达式都会创建一个小的ParseResults对象;如果这是大表达式的一部分,那么该表达式使用+ =运算符将这些片段累积到一个大的ParseResults中。

在您的情况下,您可以通过创建包含“1”的小ParseResults并将其添加到t来附加到传入的ParseResults:

t += ParseResults("1")

不幸的是,这不能用作lambda - 你可以尝试

lambda s,l,t: t.__iadd__(ParseResults("1"))

但这感觉有点太聪明了。

您可能还需要重新考虑一下解析器,以利用Optional类。将您的尾随数字视为可选元素,您可以为其定义默认值,以防缺少元素。我认为你可以用以下方式定义你想要的东西:

>>> letter = Word(alphas,exact=1)
>>> digit = Word(nums,exact=1)
>>> teststring= "a2 b5 c9 d e z"
>>> letter_and_digit = Combine(letter + Optional(digit, default="1"))
>>> print (sum(letter_and_digit.searchString(teststring)))
['a2', 'b5', 'c9', 'd1', 'e1', 'z1']

组合用于将单独的字母和数字重新加入字符串,否则每个匹配看起来都像['a','2'], ['b','5']等。

(通常,searchString返回一个ParseResults对象列表,它看起来像一个单元素列表列表。通过将searchString的结果传递给sum,这将它们全部添加到一个字符串的ParseResults中。)