在pyparsing中解析简单内容时遇到问题

6 投票
2 回答
2202 浏览
提问于 2025-04-17 06:52

我在使用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 个回答

2

如果你只是想处理一个以逗号分隔的名字列表,并且这个列表是以句号结束的,你可以使用下面的代码:

from pyparsing import *
p = Word(alphanums)+ZeroOrMore(Suppress(",")+Word(alphanums))+Suppress(".")

这样你就能得到以下结果:

>>> print p.parseString("first.")
['first']
>>> print p.parseString("first,second.")
['first', 'second']

你问题中的其他例子之所以不成功,是因为它们没有以句号结束。

6

这个“|”符号用来创建一个“优先匹配”的表达式,它会逐个检查选项,直到找到第一个匹配的结果。

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”。

撰写回答