2016-10-03 32 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