在pyparsing中解析简单内容时遇到问题
我在使用pyparsing的时候遇到了一些基本问题。下面是我的测试程序和运行的输出。
aaron-mac:sql aaron$ more s.py
from pyparsing import *
n = Word(alphanums)
a = Group( n | Group( n + OneOrMore( Suppress(",") + n )))
p = Group( a + Suppress(".") )
print a.parseString("first")
print a.parseString("first,second")
print p.parseString("first.")
print p.parseString("first,second.")
aaron-mac:sql aaron$ python s.py
[['first']]
[['first']]
[[['first']]]
Traceback (most recent call last):
File "s.py", line 15, in <module>
print p.parseString("first,second.")
File "/Library/Python/2.6/site-packages/pyparsing.py", line 1032, in parseString
raise exc
pyparsing.ParseException: Expected "." (at char 5), (line:1, col:6)
aaron-mac:sql aaron$
我该如何修改测试程序中的语法,以便解析一个以逗号分隔的名字列表,并且这个列表以句号结束呢?我查阅了文档,还试着找了一个实时支持的列表,但最后觉得在这里得到回复的可能性更大。
2 个回答
如果你只是想处理一个以逗号分隔的名字列表,并且这个列表是以句号结束的,你可以使用下面的代码:
from pyparsing import *
p = Word(alphanums)+ZeroOrMore(Suppress(",")+Word(alphanums))+Suppress(".")
这样你就能得到以下结果:
>>> print p.parseString("first.")
['first']
>>> print p.parseString("first,second.")
['first', 'second']
你问题中的其他例子之所以不成功,是因为它们没有以句号结束。
这个“|”符号用来创建一个“优先匹配”的表达式,它会逐个检查选项,直到找到第一个匹配的结果。
Pyparsing 这个工具是从左到右处理输入的,它会尽可能地将解析器的表达式应用到输入字符串上。Pyparsing 只会根据你写的解析器内容来进行前瞻检查。
在这个表达式中:
a = Group( n | Group( n + OneOrMore( Suppress(",") + n )))
假设 n
就是字面意思上的“X”。如果这个解析器接收到的输入字符串是“X”,那么它显然会匹配到开头的那个 n
表达式。如果输入是“X,X,X”,它依然只会匹配到开头的 n
,因为这是解析器中的第一个选项。
如果你把表达式反过来写成:
a = Group( Group( n + OneOrMore( Suppress(",") + n )) | n)
那么在解析“X”时,它会先尝试匹配列表,但会失败,然后再匹配单独的 n
。而在解析“X,X,X”时,第一个选项会是列表表达式,这样就能匹配成功了。
如果你想让最长的选项匹配,可以使用“^”符号,这样就变成了“或”的表达式。这个“或”会检查所有给定的选项,然后选择最长的匹配。
a = Group( n ^ Group( n + OneOrMore( Suppress(",") + n )))
你还可以使用 pyparsing 提供的一个简化方法 delimitedList
来简化这个过程。解析用逗号分隔的相同表达式的列表是一个常见的情况,所以我添加了 delimitedList
作为标准的 pyparsing 辅助工具,这样大家就不需要一次又一次地重新发明 expr + ZeroOrMore(Suppress(",") + expr)
了。使用 delimitedList("X")
可以同时匹配“X”和“X,X,X”。