pyparsing: граматика за списък с речници (erlang)

Опитвам се да създам граматика, за да анализирам списък с кортежи с маркиран Erlang и да съпоставя това с Dict в pyparsing. Имам проблеми, когато имам списък с Dicts. Граматиката работи, ако Dict има само един елемент, но когато добавя втори, сега не мога да го накарам да анализира.

Текущ (опростен граматичен код (премахнах частите от езика, които не са необходими в този случай):

#!/usr/bin/env python2.7

from pyparsing import *

# Erlang config file definition:
erlangAtom = Word( alphas + '_')
erlangString = dblQuotedString.setParseAction( removeQuotes )

erlangValue = Forward()
erlangList = Forward()

erlangElements = delimitedList( erlangValue )
erlangCSList = Suppress('[') + erlangElements + Suppress(']')
erlangList <<= Group( erlangCSList )
erlangTaggedTuple = Group( Suppress('{') + erlangAtom + Suppress(',') +
                           erlangValue + Suppress('}') )
erlangDict = Dict( Suppress('[') + delimitedList( erlangTaggedTuple ) + 
                   Suppress(']') )

erlangValue <<= ( erlangAtom | erlangString |
                  erlangTaggedTuple |
                  erlangDict | erlangList )

if __name__ == "__main__":
    working = """
[{foo,"bar"}, {baz, "bar2"}]
"""

    broken = """
[
    [{foo,"bar"}, {baz, "bar2"}],
    [{foo,"bob"}, {baz, "fez"}]
]
"""
    w = erlangValue.parseString(working)
    print w.dump()

    b = erlangValue.parseString(broken)
    print "b[0]:", b[0].dump()
    print "b[1]:", b[1].dump()

Това дава:

[['foo', 'bar'], ['baz', 'bar2']]
- baz: bar2
- foo: bar

b[0]: [['foo', 'bar'], ['baz', 'bar2'], ['foo', 'bob'], ['baz', 'fez']]
- baz: fez
- foo: bob

b[1]:
Traceback (most recent call last):
  File "./erl_testcase.py", line 39, in <module>
    print "b[1]:", b[1].dump()
  File "/Library/Python/2.7/site-packages/pyparsing.py", line 317, in __getitem__
    return self.__toklist[i]
IndexError: list index out of range

т.е. working работи, но broken не анализира като два списъка.

Някакви идеи?

Редактиране: Променен тестов случай, за да бъде по-ясен относно очаквания резултат.


person DaveR    schedule 26.02.2014    source източник
comment
Можете ли да добавите кода, който всъщност отпечатва изхода ви?   -  person Nathaniel Waisbrot    schedule 27.02.2014
comment
Имам - вижте долната част на примера (print erlangValue.parseString(working).dump())   -  person DaveR    schedule 27.02.2014


Отговори (2)


Добре, така че никога преди не съм работил с pyparsing, така че ме извинете, ако моето решение няма смисъл. Ето ни:

Доколкото разбирам това, от което се нуждаете, са три основни структури. Най-честата грешка, която сте правили, е групирането на разделени списъци. Те вече са групирани, така че имате проблем с двойното групиране. Ето моите определения:

за {a,"b"}:

erlangTaggedTuple = Dict(Group(Suppress('{') + erlangAtom + Suppress(',') + erlangValue + Suppress('}') ))

за [{a,"b"}, {c,"d"}]:

erlangDict = Suppress('[') + delimitedList( erlangTaggedTuple ) + Suppress(']')

за останалите:

erlangList <<= Suppress('[') + delimitedList( Group(erlangDict|erlangList) ) + Suppress(']')

Така че моята корекция за вашия код е:

#!/usr/bin/env python2.7

from pyparsing import *

# Erlang config file definition:
erlangAtom = Word( alphas + '_')
erlangString = dblQuotedString.setParseAction( removeQuotes )

erlangValue = Forward()
erlangList = Forward()

erlangTaggedTuple = Dict(Group(Suppress('{') + erlangAtom + Suppress(',') +
                           erlangValue + Suppress('}') ))
erlangDict = Suppress('[') + delimitedList( erlangTaggedTuple ) + Suppress(']') 
erlangList <<= Suppress('[') + delimitedList( Group(erlangDict|erlangList) ) + Suppress(']')

erlangValue <<= ( erlangAtom | erlangString |
                  erlangTaggedTuple |
                  erlangDict| erlangList )

if __name__ == "__main__":
    working = """
[{foo,"bar"}, {baz, "bar2"}]
"""

    broken = """
[
    [{foo,"bar"}, {baz, "bar2"}],
    [{foo,"bob"}, {baz, "fez"}]
]
"""
    w = erlangValue.parseString(working)
    print w.dump()

    b = erlangValue.parseString(broken)
    print "b[0]:", b[0].dump()
    print "b[1]:", b[1].dump()

Което дава резултата:

[['foo', 'bar'], ['baz', 'bar2']]
- baz: bar2
- foo: bar
b[0]: [['foo', 'bar'], ['baz', 'bar2']]
- baz: bar2
- foo: bar
b[1]: [['foo', 'bob'], ['baz', 'fez']]
- baz: fez
- foo: bob

Надявам се това да помогне, наздраве!

person user3387819    schedule 07.03.2014
comment
Това е страхотно - благодаря! Всичко изглежда добре с малкия тестов случай; надявам се, че мога да разбера как да разширя това до пълната граматика. Баунти заслужено :) - person DaveR; 08.03.2014
comment
Радвам се, че мога да помогна :) - person user3387819; 08.03.2014

Не мога да разбера защо не работи, защото вашият код изглежда много като JSON пример, който обработва добре вложените списъци.

Но проблемът изглежда се случва на тази линия

erlangElements = delimitedList( erlangValue )

където, ако erlangValues са списъци, те се добавят вместо cons'd. Можете да се занимавате с това с

erlangElements = delimitedList( Group(erlangValue) )

което добавя допълнителен слой от списък около най-горния елемент, но предпазва вашите подсписъци от сливане.

person Nathaniel Waisbrot    schedule 27.02.2014
comment
Така че, ако направя това, тогава pyparsing групира (а не обединява списъците), но речникът все още не се анализира: ` [[[['foo', 'bar'], ['baz', 'bar2'] ], [['foo', 'bob'], ['baz', 'fez']]]]` - person DaveR; 27.02.2014
comment
Той анализира за мен. Вие обаче не получавате един речник. Получавате списък, съдържащ списък от два речника. Така че result[0][0] и result[0][1] са вашите два изречения. (Очаквате ли нещо друго?) - person Nathaniel Waisbrot; 27.02.2014
comment
Това може да работи за мен (ще трябва да проверя отново по-голямата граматика), но добавянето на допълнително ниво на списъци означава, че структурата на данните на Erlang не се съпоставя чисто с Python, което е проблематично. Работата е там, че не разбирам защо текущият код не работи правилно - той вече има Group() в дефиницията на erlangList... - person DaveR; 28.02.2014
comment
Така че се върнах към примера с JSON, но той страда от абсолютно същия проблем - вижте stackoverflow.com/questions/22081239/ Така че или напълно пропускаме нещо, или това е нещо фундаментално в pyparsing... - person DaveR; 28.02.2014