Seite 1 von 1

Zeile splitten mit csv-Modul

Verfasst: Donnerstag 9. August 2007, 11:12
von gagei
Hallo,

ich möchte Zeilen in ihre Bestandteile zerlegen, die so aufgebaut sind:
  • attr1=wert1 attr2=wert2 attr3=wert3
Letztlich möchte ich ein Dictionary dieser Art erhalten:

Code: Alles auswählen

{'attr1': 'wert1', 'attr2': 'wert2', 'attr3': 'wert3'}
Das lässt sich ja leicht mit einem doppelten 'split' realisieren. Was tut man aber, wenn die Zeile so aussieht?
  • attr1=wert1 attr2="wert2 mit Leerzeichen" attr3=wert3
Ich habe dies mit dem csv-Modul versucht. Dies funktioniert aber nicht wie gewünscht:

Code: Alles auswählen

import csv
line = 'attr1=wert1 attr2="wert2 mit Leerzeichen" attr3=wert3'
for row in csv.reader([line], delimiter=' '):
    print row
ergibt

Code: Alles auswählen

['attr1=wert1', 'attr2="wert2', 'mit', 'Leerzeichen"', 'attr3=wert3']
Funktionieren würde dies, wenn die Zeile so aussieht:
  • attr1=wert1 "attr2=wert2 mit Leerzeichen" attr3=wert3
ergibt mit obigen Codezeilen:

Code: Alles auswählen

['attr1=wert1', 'attr2=wert2 mit Leerzeichen', 'attr3=wert3']
Sogar dies funktioniert:
  • attr1=wert1 "attr2=wert2 mit "Leerzeichen attr3=wert3
egibt:

Code: Alles auswählen

['attr1=wert1', 'attr2=wert2 mit Leerzeichen', 'attr3=wert3']
Aber eben nicht, wenn zwischen dem Leerzeichen und dem einleitenden Anführungszeichen schon etwas anderes steht.

Die Verwendung des csv-Moduls hat außerdem den Nachteil, dass man als Trennzeichen keinen regulären Ausdruck wie '\s+' verwenden kann, damit alternativ zum Leerzeichen auch Tabs als Trennzeichen vorkommen dürfen. Aber dies ist in diesem Fall verschmerzbar.

Wie kann ich die Zeilen splitten, ohne dass ich die Zeile zeichenweise einlese?

Gruß, Ingo

Verfasst: Donnerstag 9. August 2007, 13:06
von BlackJack
Das ist alles ein wenig zu komplex für richtig einfache Lösungen. Da wirst Du entweder ein paar Einschränkungen machen müssen, zum Beispiel das entweder nie Leerzeichen vor und nach dem '=' stehen dürfen, oder immer welche stehen müssen, dann kann man eine Lösung auf `shlex.split()` aus der Standardbibliothek aufbauen.

Oder Du musst einen Parser selbst schreiben oder eine entsprechende Bibliothek wie `pyparsing` verwenden. Eine Lösung mit letzterem könnte so aussehen:

Code: Alles auswählen

from pyparsing import (alphanums, Dict, Group, OneOrMore, QuotedString,
                       Suppress, Word)


def make_grammar():
    word = Word(alphanums)
    value = QuotedString('"') | word
    item = Group(word + Suppress('=') + value)
    items = Dict(OneOrMore(item))
    return items


def main():
    source = 'attr1=wert1 attr2="wert2 mit Leerzeichen"  attr3 = wert3'
    parser = make_grammar()
    print parser.parseString(source).asDict()
Ausgabe:

Code: Alles auswählen

{'attr2': 'wert2 mit Leerzeichen', 'attr3': 'wert3', 'attr1': 'wert1'}