我试图使用pyparsing解析来自维基百科信息框的数据字段。首先,以下代码有效:
from pyparsing import *
test_line = """{{Infobox company | name = Exxon Mobil Corp | num_employees_year = 2015 }}"""
data_group = Group(
Suppress("|") +
OneOrMore(White()).suppress() +
Word(alphanums + printables)("key") +
OneOrMore(White()).suppress() +
Suppress("=") +
OneOrMore(White()).suppress() +
OneOrMore(Word(alphanums))("value") +
ZeroOrMore(White()).suppress()
)
infobox_parser = (
Literal("{{").suppress() +
Word("Infobox") +
White().suppress() +
Word("company") +
OneOrMore(White()).suppress() +
OneOrMore(data_group)("values") +
Literal("}}").suppress()
)
print(infobox_parser.parseString(test_line))
产生结果:
['Infobox', 'company', ['name', 'Exxon', 'Mobil', 'Corp'], ['num_employees_year', '2015']]
问题是当我将测试字符串更改为
时test_line = """{{Infobox company | name = Exxon Mobil Corp. | num_employees_year = 2015 }}"""
它失败了,因为我介绍了'。'作为' Corp。'的一部分。我以为我可以通过将Group对象更改为
来解决这个问题data_group = Group(
Suppress("|") +
OneOrMore(White()).suppress() +
Word(alphanums + printables)("key") +
OneOrMore(White()).suppress() +
Suppress("=") +
OneOrMore(White()).suppress() +
OneOrMore(Word(alphanums + printables))("value") +
ZeroOrMore(White()).suppress()
)
但我收到以下错误:
pyparsing.ParseException: Expected "}}" (at char 91), (line:1, col:92)
我在这里缺少什么?提前谢谢。
答案 0 :(得分:2)
只是一些事情。最重要的是,pyparsing不像正则表达式那样进行相同的回溯。也就是说,这样的事情是行不通的:
data = '{' + OneOrMore(Word(printables))("data") + '}'
print(data.parseString('{ this is some data }'))
为什么呢?由于终止'}'也与Word(printables)
匹配,因此OneOrMore
将一直持续到最后,然后失败,因为没有终止'}'到在阅读数据后找到。
直到最近,解决方案是在OneOrMore
表达式中包含一个警卫,一个负面的说法实际上说“我想要Word(printables),但首先检查它是否是'}' - 我不喜欢我想要“,看起来像这样:
data = '{' + OneOrMore(~Literal('}') + Word(printables))("data") + '}'
但这很常见,我最近在stopOn
和ZeroOrMore
添加了一个可选的OneOrMore
参数:
data = '{' + OneOrMore(Word(printables), stopOn=Literal('}'))("data") + '}'
在您的情况下,每个data_group解析一个key=value
对,当您只解析OneOrMore(Word(alphanums))
时,您的值很好。但是一旦你把它改成OneOrMore(Word(alphanums+printables))
,你的重复术语就会贪婪地匹配下一个'|'或者终止'}}',并且就像上面的例子一样失败。
其他几项:
pyparsing会为你跳过空格。所有那些White()元素都是完全没必要的。
在某些地方,您使用Word的方式不正确,如Word("Infobox")
中所示。在您的有限示例中,这匹配正常,但请记住Word是使用您希望作为单词组匹配的字符集定义的,因此Word("Infobox")
不仅会匹配“Infobox”,还会匹配任何其他单词由字母'I','n','f','o','b'和/或'x'组成,例如“Inbox”,“IbIx”,“xoxoxox”等。在此例如,您想要的pyparsing课程为Literal
或Keyword
。
退一步,看起来你的data_groups是key=value
对,并且分隔'|'。我建议您使用delimitedList
。
最后,使用dump()
输出已解析的数据,它将有助于可视化结构和结果名称。
通过这些更改,您的代码如下所示:
data_group = Group(
Word(alphas, alphanums+'_')("key") +
Suppress("=") +
originalTextFor(OneOrMore(Word(printables), stopOn=Literal('|') | '}}'))("value")
)
infobox_parser = (
Literal("{{").suppress() +
Keyword("Infobox") +
Keyword("company") + '|' +
Group(delimitedList(data_group, '|'))("values") +
Literal("}}").suppress()
)
print(infobox_parser.parseString(test_line).dump())
,并提供:
['Infobox', 'company', '|', [['name', 'Exxon Mobil Corp.'], ['num_employees_year', '2015']]]
- values: [['name', 'Exxon Mobil Corp.'], ['num_employees_year', '2015']]
[0]:
['name', 'Exxon Mobil Corp.']
- key: name
- value: Exxon Mobil Corp.
[1]:
['num_employees_year', '2015']
- key: num_employees_year
- value: 2015