Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare ist ein Scribd-Unternehmen logo
Pyparsing

Tobias Schlauch, DLR Simulations- und Softwaretechnik
Python User Group Köln 14. Mai 2008




                                                   Folie 1
Motivation


  DataFinder
       Software zum Management wissenschaftlich-technischer Daten
       Implementierung in Python und Qt
  Problem
       Vereinfachung des DataFinder-API zur Suche in Metadaten erforderlich
       Anstatt Syntax mit Hilfe definierter Klassen abzubilden, soll einfache
       Verwendung von Zeichenketten ausreichen, wie z.B.
       projectName = quot;X-38quot; and author = quot;Schüttequot;
  Lösungvariante
       Reguläre Ausdrücke
       Schön… aber was macht das hier eigentlich???
       quot;[-+]?(d+(.d*)?|.d+)([eE][-+]?d+)?quot;
  Alternativen…?



                                                                                Folie 2
Pyparsing im Überblick


  Was ist Pyparsing?
       Klassenbibliothek zur Erstellung von Parsern (recursive descent)
       Design auf einfache Erstellung und Aktualisierung ausgelegt
       Parser für regulären Sprachen und Teilmenge kontextfreier
       Sprachen (vgl. Chomsky-Hierarchie)


  Pure-Python, Python >= 2.3.2


  MIT-Lizenz


  Gute Dokumentation
       Epydoc, Klassendiagramm, Beispiele, Wiki


                                                                      Folie 3
Was macht eigentlich ein Parser? (vereinfacht)

                                        Zeichenstrom
          |H|e|l|l|o|,|Wo|r|l|d|!|




             „Hello,World!“-Parser
              Syntaktisch korrekt?




                                     Abgeleitete Token
              |Hello|,|World|!|



                                                         Folie 4
Grundlegende Vorgehensweise mit Pyparsing


1.   Definition der Grammatik (Token / Verknüpfungen)
           Hierarchische Definition
           Optionale Definition von Ergebnisnamen und Parseraktionen

2.   Aufruf von parseString oder scanString
          Standardmäßig werden Whitespaces ignoriert
          Anwendung definierter Parseraktionen


3.   Verarbeitung des Ergebnisses als Liste oder unter Verwendung der
     definierter Namen




                                                                        Folie 5
Erstes Beispiel
Hello World!

  Definition der Token / Muster
  greeting = oneOf(quot;Hello Hiquot;) + Literal(quot;,quot;) +
                  Word(alphas) + Literal(quot;!quot;)


  Aufruf von parseString()
  print greeting.parseString(quot;Hello, World!quot;).asList()
  ['Hello', ',', 'World', '!']


  print greeting.parseString(„Hi, SISTECquot;)
  pyparsing.ParseException: Expected quot;!quot; (at char 13),
  (line:1, col:14)
  Ups „!“ vergessen



                                                     Folie 6
Pyparsing Grundlagen
Definition fester Token

  Literal / CaselessLiteral
        ifToken = Literal(quot;ifquot;)
       Findet das Token in if(x=1) und in ifAndOnlyYouAndMe


  Keyword / CaselessKeyword
      ifToken = Keyword(quot;ifquot;)
      Findet das Token in if(x=1), aber nicht in
      ifAndOnlyYouAndMe


  Caseless-Varianten geben als Ergebnis immer die definierte Variante
  zurück, also hier if




                                                                        Folie 7
Pyparsing Grundlagen
Definition variabler Token

  Word – Definition durch erlaubte Zeichen
      name = Word(quot;Tabiosquot;)
      name = Word(quot;Tquot;, quot;abiosquot;)


  CharsNotIn – Definition durch nicht erlaubter Zeichen
       name = CharsNotIn(quot;,;:-!quot;)
  Zusätzlich Spezifikation der Länge möglich (min, max, exakt)


  Regex
      Erwartet als Parameter einen regulären Ausdruck, wie für das
      Standardmodul re
       Vorher nach Pyparsing-Lösung suchen!!!


                                                                     Folie 8
Pyparsing Grundlagen
Verknüpfungen
  And (+) – Definition erforderlicher Ausdrücke in fester Reihenfolge
       sentence = And([subject, verb, object])
       sentence = subject + verb + object

  Each (&) – Definition erforderlicher Ausdrücke in beliebiger Reihenfolge
       identity = persNumber & name

  Or (^) – Definition alternativer Ausdrücke (Priorität: Zeichenkettenlänge)
        operator = Literal(quot;<quot;) ^ Literal(quot;<=quot;)

  MatchFirst (|) – Definition alternativer Ausdrücke (Priorität: Definitions-
  reihenfolge)
       operator = Literal(quot;<=quot;) | Literal(quot;<quot;)


                                                                                Folie 9
Pyparsing Grundlagen
Optionale Ausdrücke, Wiederholungen

  Optional
       Definition optionaler Ausdrücke
       dateTime = day + quot;.quot; + month + quot;.quot; + year +
                       Optional(time)


  ZeroOrMore
       Ähnlich zu Optional, aber erlaubt Wiederholungen
       logMsg = dateTime + ZeroOrMore(Word(alphas))


  OneOrMore
      Ähnlich zu ZeroOrMore, aber erfordert mindestens einen Treffer
      logMsg = dateTime + OneOrMore(Word(alphas))


                                                                   Folie 10
Pyparsing Grundlagen
Konvertierungen
  Upcase - Konvertierung in Großbuchstaben

  Suppress - Unterdrückung von Token
      date = day + Suppress(quot;.quot;) + month +
                Suppress(quot;.quot;) + year
      print date.parseString(quot;11.03.2008quot;).asList()
      [quot;11quot;, quot;03quot;, quot;2008quot;]

  Combine – Verbindet einzelne Token zu einer Zeichenkette
      date = Combine(day + quot;.quot; + month + quot;.quot; + year)
      print date.parseString(quot;11.03.2008quot;).asList()
      [quot;11.03.2008quot;] anstatt
      [quot;11quot;, quot;.quot;, quot;03quot;, quot;.quot;, quot;2008quot;] (ohne Combine)


                                                             Folie 11
Pyparsing Grundlagen
Rekursive Grammatiken

  Forward – Platzhalter zur Definition rekursiver Grammatiken
  Beispiel Parsen einer Liste
  list = Forward()
  listItem = Word(alphas)
  list << (listItem + Suppress(Literal(quot;,quot;)) + list |
              listItem)


  print list.parseString(quot;Wert          , Name, testquot;).asList()
  [quot;Wertquot;, quot;Namequot;, quot;testquot;]
       Klammerung beachten! (Operator | bindet stärker als <<)

  Überprüfung auf Endlosrekursion durch Aufruf von validate()


                                                                 Folie 12
Pyparsing Grundlagen
Parseraktionen

  Erlaubt Änderung der erkannten Token während des Parsevorgangs
       Hinzufügen / Entfernen von Informationen
       Konvertierungen
       …
  3 Schnittstellen
       f(t); t – Liste erkannter Token
       f(l, t); l – Position im zu parsenden String
       f(s, l, t); s – Zu parsender String
  Hilfsfunktionen
        replaceWith(replaceString)
        removeQuotes()
        …

                                                                   Folie 13
Pyparsing Grundlagen
Parseraktionen - Beispiel
  Definition einer Aktion zur Konvertierung
  def convertNumValue(t):
     numValue = t.asList()[0]
    try:
        return int(numValue)
     except ValueError:
        return float(numValue)
  Anhängen der Aktion
   numValue.setParseAction(convertNumValue) oder
   numValue.addParseAction(convertNumValue)
  Ergebnis
   print numValue.parseString(quot;12340quot;).asList()
   [12340] anstatt [quot;12340quot;]


                                                   Folie 14
Pyparsing Grundlagen
Hilfsfunktionen (kleine Auswahl)

  oneOf – Vereinfachte Definition von Alternativen
  options = oneOf(quot;< > <= = >=quot;)


  delimitedList – Parsen von Listen
  list = delimitedList(Word(alphas), quot;,quot;)


  nestedExpr – Parsen von verschalteten Ausdrücken
  nested = nestedExpr(quot;(quot;, quot;)quot;, Word(alphas))
  print nested.parseString(quot;(abc(def(gh)))quot;).asList()
  [[quot;abcquot;, [quot;defquot;, [quot;ghquot;]]]]


  operatorPrecedence – Parsen von Operatorrangfolgen (später mehr)

                                                                     Folie 15
Pyparsing Grundlagen
Verarbeitung von Ergebnissen

  Geparste Token werden in einer hierarchischen Struktur zurückgegeben
  (ParsingResults)


  Verarbeitung der Token als Listen, XML, Dictionary oder über die
  Objekteigenschaften möglich
       Verarbeitung als Dictionary oder über Objekteigenschaften setzt
       Benennung der Ergebnisse bei der Definition voraus
       Überschaubarer Grammatiken -> Benennung nicht unbedingt
       erforderlich
       Komplexer Grammatiken -> Benennung empfohlen




                                                                     Folie 16
Pyparsing Grundlagen
Verarbeitung von Ergebnissen - Beispiel
  Definition der Token / Muster
  date = day.setResultsName(quot;dayquot;) + quot;.quot; +
            month.setResultsName(quot;monthquot;) + quot;.quot; +
            year.setResultsName(quot;yearquot;)
  token = date.parseString(quot;11.03.2008quot;)
  Ausgaben
  print token.asList()
  [quot;11quot;, quot;.quot;, quot;03quot;, quot;.quot;, quot;2008quot;]
  print token.asXML()
  quot;<ITEM><day>11</day><ITEM>quot;.quot;</ITEM><month…quot;
  print token.asDict()
  {quot;dayquot;: quot;11quot;, quot;monthquot;: quot;03quot;, quot;yearquot;: quot;2008quot;}
  print token.day
  quot;11quot;


                                                    Folie 17
Pyparsing Grundlagen
…

  Pyparsing enthält noch etliche Details, die aber den Rahmen dieses
  Vortrags sprengen, z.B.:
       Ergebnisgruppierungen Group, Dict


       Weitere Hilfsfunktionen
            Verarbeitung XML, HTML
            Positionsabhängige Hilfsfunktionen


       Tokenkonstanten (z.B. für Kommentare)




                                                                       Folie 18
Performance-Tuning


  Aktivierung von Packrat-Parsing (enablePackrat)
  Verwendung von Psyco (http://psyco.sourceforge.net/)


     Verliog-Parser            Python V2.4.1   Python V2.5
                               (lines parsed   (lines parsed
                               /second)        /second)
     base                      160.6           146.5
     packrat                   428.7           395.8
     psyco                     365.7           - n/a -
     packrat + psyco           614.4           - n/a -



   Quelle: http://pyparsing.wikispaces.com/News

                                                               Folie 19
Suchrestriktionen im DataFinder
Definition der Grammatik (stark vereinfacht)
literal = QuotedString(quot;'quot;)
propertyName = Word(alphas)
comparisionTerm = propertyName + oneOf(quot;< > <= => =quot;) +
                  literal

searchRestriction = operatorPrecedence(comparisionTerm,
                     [(quot;notquot;, 1, opAssoc.RIGHT),
                      (quot;andquot;, 2, opAssoc.LEFT),
                      (quot;orquot;, 2, opAssoc.LEFT)])
   Beispiel
   myRestr = quot;a > 'test' and not(b < '3')quot;
   print searchRestriction.parseString(myRestr).asList()
   [[quot;aquot;, quot; >quot;, quot;testquot;, quot;andquot;, [quot;notquot;, quot;bquot;, quot;<quot;, quot;3quot;]]]


                                                      Folie 20
Suchrestriktionen im DataFinder
Anwendung

  Zentrale Grammatikdefinition wird genutzt für
       Transformation der geparsten Token auf Syntax der Bibliothek,
       welche intern zur Suchabfrage genutzt wird
       Syntax-Highlighting




                                                                       Folie 21
Vielen Dank! Fragen??


  Pyparsing Links
       News: http://pyparsing.wikispaces.com/News
       Beispiele: http://pyparsing.wikispaces.com/Examples
       Download:
       http://sourceforge.net/project/showfiles.php?group_id=97203
  Weiterführendes zum Thema:
       Compilerbau: http://de.wikipedia.org/wiki/Compilerbau
       Aho, Sethi, Ullman: Compilerbau, Tl. 1. Oldenbourg, 1999
       Recursive Descent Parser:
       http://en.wikipedia.org/wiki/Recursive_descent_parser
       Packrat-Parsing: http://pdos.csail.mit.edu/~baford/packrat/
       Alternative Python-Parsersysteme: http://pythonsource.com/open-
       source/parser-generators

                                                                     Folie 22

Weitere ähnliche Inhalte

Pyparsing

  • 1. Pyparsing Tobias Schlauch, DLR Simulations- und Softwaretechnik Python User Group Köln 14. Mai 2008 Folie 1
  • 2. Motivation DataFinder Software zum Management wissenschaftlich-technischer Daten Implementierung in Python und Qt Problem Vereinfachung des DataFinder-API zur Suche in Metadaten erforderlich Anstatt Syntax mit Hilfe definierter Klassen abzubilden, soll einfache Verwendung von Zeichenketten ausreichen, wie z.B. projectName = quot;X-38quot; and author = quot;Schüttequot; Lösungvariante Reguläre Ausdrücke Schön… aber was macht das hier eigentlich??? quot;[-+]?(d+(.d*)?|.d+)([eE][-+]?d+)?quot; Alternativen…? Folie 2
  • 3. Pyparsing im Überblick Was ist Pyparsing? Klassenbibliothek zur Erstellung von Parsern (recursive descent) Design auf einfache Erstellung und Aktualisierung ausgelegt Parser für regulären Sprachen und Teilmenge kontextfreier Sprachen (vgl. Chomsky-Hierarchie) Pure-Python, Python >= 2.3.2 MIT-Lizenz Gute Dokumentation Epydoc, Klassendiagramm, Beispiele, Wiki Folie 3
  • 4. Was macht eigentlich ein Parser? (vereinfacht) Zeichenstrom |H|e|l|l|o|,|Wo|r|l|d|!| „Hello,World!“-Parser Syntaktisch korrekt? Abgeleitete Token |Hello|,|World|!| Folie 4
  • 5. Grundlegende Vorgehensweise mit Pyparsing 1. Definition der Grammatik (Token / Verknüpfungen) Hierarchische Definition Optionale Definition von Ergebnisnamen und Parseraktionen 2. Aufruf von parseString oder scanString Standardmäßig werden Whitespaces ignoriert Anwendung definierter Parseraktionen 3. Verarbeitung des Ergebnisses als Liste oder unter Verwendung der definierter Namen Folie 5
  • 6. Erstes Beispiel Hello World! Definition der Token / Muster greeting = oneOf(quot;Hello Hiquot;) + Literal(quot;,quot;) + Word(alphas) + Literal(quot;!quot;) Aufruf von parseString() print greeting.parseString(quot;Hello, World!quot;).asList() ['Hello', ',', 'World', '!'] print greeting.parseString(„Hi, SISTECquot;) pyparsing.ParseException: Expected quot;!quot; (at char 13), (line:1, col:14) Ups „!“ vergessen Folie 6
  • 7. Pyparsing Grundlagen Definition fester Token Literal / CaselessLiteral ifToken = Literal(quot;ifquot;) Findet das Token in if(x=1) und in ifAndOnlyYouAndMe Keyword / CaselessKeyword ifToken = Keyword(quot;ifquot;) Findet das Token in if(x=1), aber nicht in ifAndOnlyYouAndMe Caseless-Varianten geben als Ergebnis immer die definierte Variante zurück, also hier if Folie 7
  • 8. Pyparsing Grundlagen Definition variabler Token Word – Definition durch erlaubte Zeichen name = Word(quot;Tabiosquot;) name = Word(quot;Tquot;, quot;abiosquot;) CharsNotIn – Definition durch nicht erlaubter Zeichen name = CharsNotIn(quot;,;:-!quot;) Zusätzlich Spezifikation der Länge möglich (min, max, exakt) Regex Erwartet als Parameter einen regulären Ausdruck, wie für das Standardmodul re Vorher nach Pyparsing-Lösung suchen!!! Folie 8
  • 9. Pyparsing Grundlagen Verknüpfungen And (+) – Definition erforderlicher Ausdrücke in fester Reihenfolge sentence = And([subject, verb, object]) sentence = subject + verb + object Each (&) – Definition erforderlicher Ausdrücke in beliebiger Reihenfolge identity = persNumber & name Or (^) – Definition alternativer Ausdrücke (Priorität: Zeichenkettenlänge) operator = Literal(quot;<quot;) ^ Literal(quot;<=quot;) MatchFirst (|) – Definition alternativer Ausdrücke (Priorität: Definitions- reihenfolge) operator = Literal(quot;<=quot;) | Literal(quot;<quot;) Folie 9
  • 10. Pyparsing Grundlagen Optionale Ausdrücke, Wiederholungen Optional Definition optionaler Ausdrücke dateTime = day + quot;.quot; + month + quot;.quot; + year + Optional(time) ZeroOrMore Ähnlich zu Optional, aber erlaubt Wiederholungen logMsg = dateTime + ZeroOrMore(Word(alphas)) OneOrMore Ähnlich zu ZeroOrMore, aber erfordert mindestens einen Treffer logMsg = dateTime + OneOrMore(Word(alphas)) Folie 10
  • 11. Pyparsing Grundlagen Konvertierungen Upcase - Konvertierung in Großbuchstaben Suppress - Unterdrückung von Token date = day + Suppress(quot;.quot;) + month + Suppress(quot;.quot;) + year print date.parseString(quot;11.03.2008quot;).asList() [quot;11quot;, quot;03quot;, quot;2008quot;] Combine – Verbindet einzelne Token zu einer Zeichenkette date = Combine(day + quot;.quot; + month + quot;.quot; + year) print date.parseString(quot;11.03.2008quot;).asList() [quot;11.03.2008quot;] anstatt [quot;11quot;, quot;.quot;, quot;03quot;, quot;.quot;, quot;2008quot;] (ohne Combine) Folie 11
  • 12. Pyparsing Grundlagen Rekursive Grammatiken Forward – Platzhalter zur Definition rekursiver Grammatiken Beispiel Parsen einer Liste list = Forward() listItem = Word(alphas) list << (listItem + Suppress(Literal(quot;,quot;)) + list | listItem) print list.parseString(quot;Wert , Name, testquot;).asList() [quot;Wertquot;, quot;Namequot;, quot;testquot;] Klammerung beachten! (Operator | bindet stärker als <<) Überprüfung auf Endlosrekursion durch Aufruf von validate() Folie 12
  • 13. Pyparsing Grundlagen Parseraktionen Erlaubt Änderung der erkannten Token während des Parsevorgangs Hinzufügen / Entfernen von Informationen Konvertierungen … 3 Schnittstellen f(t); t – Liste erkannter Token f(l, t); l – Position im zu parsenden String f(s, l, t); s – Zu parsender String Hilfsfunktionen replaceWith(replaceString) removeQuotes() … Folie 13
  • 14. Pyparsing Grundlagen Parseraktionen - Beispiel Definition einer Aktion zur Konvertierung def convertNumValue(t): numValue = t.asList()[0] try: return int(numValue) except ValueError: return float(numValue) Anhängen der Aktion numValue.setParseAction(convertNumValue) oder numValue.addParseAction(convertNumValue) Ergebnis print numValue.parseString(quot;12340quot;).asList() [12340] anstatt [quot;12340quot;] Folie 14
  • 15. Pyparsing Grundlagen Hilfsfunktionen (kleine Auswahl) oneOf – Vereinfachte Definition von Alternativen options = oneOf(quot;< > <= = >=quot;) delimitedList – Parsen von Listen list = delimitedList(Word(alphas), quot;,quot;) nestedExpr – Parsen von verschalteten Ausdrücken nested = nestedExpr(quot;(quot;, quot;)quot;, Word(alphas)) print nested.parseString(quot;(abc(def(gh)))quot;).asList() [[quot;abcquot;, [quot;defquot;, [quot;ghquot;]]]] operatorPrecedence – Parsen von Operatorrangfolgen (später mehr) Folie 15
  • 16. Pyparsing Grundlagen Verarbeitung von Ergebnissen Geparste Token werden in einer hierarchischen Struktur zurückgegeben (ParsingResults) Verarbeitung der Token als Listen, XML, Dictionary oder über die Objekteigenschaften möglich Verarbeitung als Dictionary oder über Objekteigenschaften setzt Benennung der Ergebnisse bei der Definition voraus Überschaubarer Grammatiken -> Benennung nicht unbedingt erforderlich Komplexer Grammatiken -> Benennung empfohlen Folie 16
  • 17. Pyparsing Grundlagen Verarbeitung von Ergebnissen - Beispiel Definition der Token / Muster date = day.setResultsName(quot;dayquot;) + quot;.quot; + month.setResultsName(quot;monthquot;) + quot;.quot; + year.setResultsName(quot;yearquot;) token = date.parseString(quot;11.03.2008quot;) Ausgaben print token.asList() [quot;11quot;, quot;.quot;, quot;03quot;, quot;.quot;, quot;2008quot;] print token.asXML() quot;<ITEM><day>11</day><ITEM>quot;.quot;</ITEM><month…quot; print token.asDict() {quot;dayquot;: quot;11quot;, quot;monthquot;: quot;03quot;, quot;yearquot;: quot;2008quot;} print token.day quot;11quot; Folie 17
  • 18. Pyparsing Grundlagen … Pyparsing enthält noch etliche Details, die aber den Rahmen dieses Vortrags sprengen, z.B.: Ergebnisgruppierungen Group, Dict Weitere Hilfsfunktionen Verarbeitung XML, HTML Positionsabhängige Hilfsfunktionen Tokenkonstanten (z.B. für Kommentare) Folie 18
  • 19. Performance-Tuning Aktivierung von Packrat-Parsing (enablePackrat) Verwendung von Psyco (http://psyco.sourceforge.net/) Verliog-Parser Python V2.4.1 Python V2.5 (lines parsed (lines parsed /second) /second) base 160.6 146.5 packrat 428.7 395.8 psyco 365.7 - n/a - packrat + psyco 614.4 - n/a - Quelle: http://pyparsing.wikispaces.com/News Folie 19
  • 20. Suchrestriktionen im DataFinder Definition der Grammatik (stark vereinfacht) literal = QuotedString(quot;'quot;) propertyName = Word(alphas) comparisionTerm = propertyName + oneOf(quot;< > <= => =quot;) + literal searchRestriction = operatorPrecedence(comparisionTerm, [(quot;notquot;, 1, opAssoc.RIGHT), (quot;andquot;, 2, opAssoc.LEFT), (quot;orquot;, 2, opAssoc.LEFT)]) Beispiel myRestr = quot;a > 'test' and not(b < '3')quot; print searchRestriction.parseString(myRestr).asList() [[quot;aquot;, quot; >quot;, quot;testquot;, quot;andquot;, [quot;notquot;, quot;bquot;, quot;<quot;, quot;3quot;]]] Folie 20
  • 21. Suchrestriktionen im DataFinder Anwendung Zentrale Grammatikdefinition wird genutzt für Transformation der geparsten Token auf Syntax der Bibliothek, welche intern zur Suchabfrage genutzt wird Syntax-Highlighting Folie 21
  • 22. Vielen Dank! Fragen?? Pyparsing Links News: http://pyparsing.wikispaces.com/News Beispiele: http://pyparsing.wikispaces.com/Examples Download: http://sourceforge.net/project/showfiles.php?group_id=97203 Weiterführendes zum Thema: Compilerbau: http://de.wikipedia.org/wiki/Compilerbau Aho, Sethi, Ullman: Compilerbau, Tl. 1. Oldenbourg, 1999 Recursive Descent Parser: http://en.wikipedia.org/wiki/Recursive_descent_parser Packrat-Parsing: http://pdos.csail.mit.edu/~baford/packrat/ Alternative Python-Parsersysteme: http://pythonsource.com/open- source/parser-generators Folie 22