2016-04-03 9 views
1

Ich habe eine Frage über verschachtelte Grammatik. Wie lassen Sie Piparsen nach verschachtelten Grammatikkonstrukten suchen?PyParsing verhält sich nicht wie erwartet mit verschachtelter Grammatik

from pyparsing import Word, alphas, alphanums, Suppress, LineEnd, LineStart, nums, Or, Group, OneOrMore, Literal, CaselessLiteral, Combine, Optional 

word = Word(alphanums+'_') 

object_type = Suppress("object ")+word.setResultsName("object_type")+Suppress('{')+LineEnd() 

point = Literal('.') 
e = CaselessLiteral('E') 
plusorminus = Literal('+') | Literal('-') 
number = Word(nums) 
integer = Combine(Optional(plusorminus) + number) 
floatnumber = Combine(integer + 
         Optional(point + Optional(number)) + 
         Optional(e + integer) 
        ) 

attribute = word.setResultsName("attribute") 
value = Or([floatnumber, word]).setResultsName("value") 

attributes = Group(attribute+value+Suppress(";")+LineEnd()) 
namespace = Group(object_type+\ OneOrMore(attributes).setResultsName("attributes") + Suppress("}")) 
all = OneOrMore(namespace).setResultsName("namespaces") 

result = all.parseString(glm) 

for n in result.namespaces: 
    print(n) 

Das folgende Beispiel zeigt etwas, das ich zum Beispiel analysieren möchte. Der erste Namespace funktioniert wie erwartet. Die Sekunde jedoch kann nicht analysiert werden. Kann mir jemand erklären, was ich vermisse?

"""object object_type1{ 
attr1 0.0111; 
name name_of_object_1; 
} 
object object_type1{ 
attr1 0.02; 
name name_of_object_2; 
    object object_type2{ 
    name name_of_object_3; 
    } 
} 
""" 

Antwort

1

Um eine rekursive Grammatik zu definieren, das heißt, eine, die eine Laufzeit hat, die selbst einen Teil seiner eigenen Definition ist, müssen Sie pyparsing die Forward Klasse. In Ihrem Fall kann eine namespace Attribute oder verschachtelte Namespaces enthalten. Um dies zu tun, müssen Sie zuerst eine Art Platzhalter definieren für namespace:

namespace = Forward() 

Dann, wenn es Zeit ist, um den Inhalt zu definieren (die namespace als Teil der Definition enthalten), verwenden Sie den <<= Operator statt =:

namespace <<= Group(object_type + OneOrMore(attributes|namespace).setResultsName("attributes") + Suppress("}")) 
all = OneOrMore(namespace).setResultsName("namespaces") 

Ansonsten sollte Ihr Parser gut funktionieren.

Nur ein paar andere Tipps:

  • Ich habe vor kurzem die pprint() Methode, den Inhalt eines ParseResults Objektauflistung aus zu vereinfachen. Versuchen Sie result.pprint() anstelle der for-Schleife, die Sie jetzt verwenden.

  • Sie brauchen nicht wirklich die Zeilenumbrüche in Ihrer Ausgabe, also ersetzen Sie alle LineEnd() Begriffe durch LineEnd().suppress() - dies wird Ihre Ergebnisse ein wenig naten.

  • Ich bin nicht sicher, dass die Ergebnisnamen in diesem Fall wirklich viel für Sie tun. Aber ich finde, dass die Verwendung von expr("name") besser lesbar ist als expr.setResultsName("name"). Aber jede Form wird in Ordnung funktionieren.

Verwandte Themen