Innerhaln eines bestimmten Bereichs splitten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
USER67
User
Beiträge: 14
Registriert: Mittwoch 22. September 2010, 10:58

Guten Tag,

Code: Alles auswählen


Sonnenschein = "Die Sonne scheint: [1, "Maier: begeistert"], Die Wolken sind grau: [2,"Udu: traurig"]"

Ich würde gerne nach ":" spliten, allerdings soll es nur oberflächlich passieren, in den Listen soll es nicht geschehen.
Wie könnte man das hinkriegen?

Mfg
Udu
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Könntest Du nicht für das Beispiel mal das von Dir gewünschte Endresultat angeben? Nur als Sicherheit, dass man Dich auch wirklich verstanden hat.

Prinzipiell müßtest Du da wohl mit einem Zustandsautomaten arbeiten (außerhalb einer Liste, oder innerhalb).
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
USER67
User
Beiträge: 14
Registriert: Mittwoch 22. September 2010, 10:58

Hallo,

ja natürlich. Also ich möchte einen vorhandenen Text analysieren.
Dabei sollen solche Fragmente in einem Dictionary abgelegt werden, wobei die oberflächlichen Statements wie "Die Sonne scheint:" als "Keys" gesetzt werden.
In der Form

Code: Alles auswählen

Dictionary = {
"Die Sonne scheint": [1, "Maier: begeistert"], 
"Die Wolken sind grau": [2,"Udu: traurig]"
...
}

BlackJack

@USER67: So etwas ist oft komplizierter als es auf den ersten Blick scheint. Wenn man Einfluss auf das erzeugende Programm hat, sollte man so etwas gar nicht erst erzeugen, sondern lieber ein standardisiertes Format verwenden, für das es bereits fertige Parser gibt. XML oder JSON zum Beispiel.

Sonst muss man sich selber einen Parser basteln, zum Beispiel mit Hilfe einer entsprechenden Bibliothek. Hier mal ein Beispiel mit `pyparsing`:

Code: Alles auswählen

from pprint import pprint
import pyparsing as pp


def main():
    sonnenschein = ('Die Sonne scheint: [1, "Maier: begeistert"],'
                    ' Die Wolken sind grau: [2,"Udu: traurig"]')
    
    key = pp.CharsNotIn(':')
    value = pp.Combine('[' + pp.CharsNotIn(']') + ']')
    item = pp.Group(key + pp.Suppress(':') + value)
    items = pp.Dict(pp.delimitedList(item))
    
    result = items.parseString(sonnenschein)
    pprint(result.asDict())


if __name__ == '__main__':
    main()
Ausgabe:

Code: Alles auswählen

$ python forum5.py
{'Die Sonne scheint': '[1, "Maier: begeistert"]',
 'Die Wolken sind grau': '[2,"Udu: traurig"]'}
Wie man sieht sind die "Listen" noch Zeichenketten. Da müsste man die Grammatik noch ein wenig erweitern.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

USER67 hat geschrieben:

Code: Alles auswählen

Sonnenschein = "Die Sonne scheint: [1, "Maier: begeistert"], Die Wolken sind grau: [2,"Udu: traurig"]"
Ich würde gerne nach ":" spliten, allerdings soll es nur oberflächlich passieren, in den Listen soll es nicht geschehen.
Erst einmal müsste der Code wie folgt aussehen:

Code: Alles auswählen

Sonnenschein = 'Die Sonne scheint: [1, "Maier: begeistert"], Die Wolken sind grau: [2,"Udu: traurig"]'
Das genannte Beispiel führt zu einem Syntaxfehler.

Jetzt sollte man auch noch klar stellen, dass es dort nirgendwo eine Liste gibt. Es gibt einen String der eckige Klammern enthält, aber das ist auch schon alles. Ich möchte hier von vorneherein sicher gehen, dass hier nicht von falschen Voraussetzungen ausgegangen wird.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also willst Du eigentlich nach den Kommata trennen, die einen Block (Text + ":" + "[]"-Ausdruck) vom anderen trennt. Erst danach willst Du ein solches Token dann am ersten ":" trennen. So interpretiere ich dein Beispiel.

Ich hätte dieses Vorgehen vorgeschlagen:

Code: Alles auswählen

In [27]: data = u"""Die Sonne scheint: [1, "Maier: begeistert"], Die Wolken sind grau: [2,"Udu: traurig"]"""

In [30]: for token in re.findall("[ \w]*: \[.*?\]", data):
   ....:     print token
   ....:     
   ....:     
Die Sonne scheint: [1, "Maier: begeistert"]
 Die Wolken sind grau: [2,"Udu: traurig"]
Damit hättest Du die Tokens. Wenn Du den RegExp erweiterst, kannst Du auch gleich die beiden Teile rausfiltern:

Code: Alles auswählen

In [34]: re.findall("(?P<key>[ \w]*): (?P<value>\[.*?\])", data)
Out[34]: 
[(u'Die Sonne scheint', u'[1, "Maier: begeistert"]'),
 (u' Die Wolken sind grau', u'[2,"Udu: traurig"]')]
Das kannst Du direkt in ein Dictionary wandeln.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

Ich würde da noch ein r'\s*' am Anfang schreiben, damit beim zweiten Shlüssel das führende Leerzeichen verschwindet.

Code: Alles auswählen

In [712]: dict(re.findall(r'\s*(?P<key>[^:]+): (?P<value>\[.*?\]),?', data))
Out[712]:
{'Die Sonne scheint': '[1, "Maier: begeistert"]',
 'Die Wolken sind grau': '[2,"Udu: traurig"]'}
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@BlackJack: Gute Idee!

Wobei mir Deine Lösung eh besser gefällt; sie ist leichter erweiterbar und vor allem auch flexibler hinsichtlich innerer Konstrukte. Wir wissen ja nicht, inwiefern die Syntax innerhalb der "[]"-Paare immer gleich bleibt.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten