2016-10-03 91 views
1

我想解析数据字段从维基百科信息使用pyparsing。首先,下面的代码工作:解析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 }}""" 

它的失败,因为我介绍了“ “。作为'公司'的一部分。我以为我可以通过改变组对象

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) 

缺少什么我在这里?提前致谢。

回答

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参数ZeroOrMoreOneOrMore

data = '{' + OneOrMore(Word(printables), stopOn=Literal('}'))("data") + '}' 

在你的情况,其中每个大ta_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',例如“收件箱”,“IbIx”,“xoxoxox”等。在这种情况下,你想要的课程将是LiteralKeyword

  • 回过头来,它看起来像你的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 
+0

感谢您抽出时间来提供这样一个详细的解答。 – John