Seite 1 von 1
Strings zu Tuple über ( und )
Verfasst: Mittwoch 16. März 2011, 13:11
von nvidia
Hallo,
wie kann ich diesen String zum Tuple an den "(" oder ")" transformieren?
//und noch eine frage
was macht die -1 da:
Re: Strings zu Tuple über ( und )
Verfasst: Mittwoch 16. März 2011, 13:25
von Dauerbaustelle
nvidia hat geschrieben:Hallo,
wie kann ich diesen String zum Tuple an den "(" oder ")" transformieren?
Kommata nach Ausführungszeichen einfügen und dann in `eval` werfen zum Beispiel.
//und noch eine frage
was macht die -1 da:
Das nach dem Doppelpunkt gibt das Ende des Slices an; ein negatives Indexwert steht in Python für "von hinten zählen".
Re: Strings zu Tuple über ( und )
Verfasst: Mittwoch 16. März 2011, 13:26
von cofi
Ad 1) Nun, `eval` existiert, dass solltest du allerdings nur einsetzen wenn du a) die Risiken kennst und b) ausschliessen kannst, dass sie ausgenutzt werden. Daneben gibt es noch das `ast`-Modul.
Ad 2) Teste es doch:
Code: Alles auswählen
In [1]: s = '("w1" "w2" ("w3" "w4") ("w5") "w6" ("w7"))'
In [2]: s[1:-1]
Out[2]: '"w1" "w2" ("w3" "w4") ("w5") "w6" ("w7")'
Re: Strings zu Tuple über ( und )
Verfasst: Mittwoch 16. März 2011, 13:57
von BlackJack
Eine Lösung mit PyParsing:
Code: Alles auswählen
from pyparsing import QuotedString, Forward, Group, Suppress, ZeroOrMore
def main():
TUPLE = Forward()
TUPLE << Group(
Suppress('(') + ZeroOrMore(QuotedString('"') | TUPLE) + Suppress(')')
).setParseAction(lambda toks: tuple(toks[0]))
ast = TUPLE.parseString('("w1" "w2" ("w3" "w4") ("w5") "w6" ("w7"))')
print ast[0]
if __name__ == '__main__':
main()
Re: Strings zu Tuple über ( und )
Verfasst: Mittwoch 16. März 2011, 13:58
von Hyperion
Hier mal mein Vorschlag:
Code: Alles auswählen
#!/usr/bin/env python
# coding: utf-8
import re
TOKENS = re.compile(r'(?P<bl>\()|(?P<br>\))|(?P<data>\w+)|\s')
def tokenize(data):
for token in re.finditer(TOKENS, data):
yield token
def loads(data):
stack = [[]]
for token in tokenize(data):
if token.group("bl"):
stack.append(list())
elif token.group("br"):
tmp = tuple(stack.pop())
stack[-1].append(tmp)
elif token.group("data"):
stack[-1].append(token.group())
else:
continue
return stack.pop().pop()
if __name__ == "__main__":
data = '("w1" "w2" ("w3" "w4") ("w5") "w6" ("w7"))'
print loads(data)
Mir missfällt dabei noch, dass ich den Stack mit einer Dummy-Liste initialisieren muss. Das finde ich spezielle am Schluss dann unschön (2x pop).
Ich vermute mal sma und BlackJack zaubern da bessere Lösungen aus dem Hut
Edit: Wußt ich's doch

Re: Strings zu Tuple über ( und )
Verfasst: Sonntag 20. März 2011, 11:29
von BlackJack
@Hyperion: Ich habe auch mal eine `re`-Lösung gebastelt, für die komplette Syntax aus dem anderen Thread mit NIL und Zahlen:
Code: Alles auswählen
import re
from pprint import pprint
SOURCE = '''\
(
("TEXT" "PLAIN" ("CHARSET" "utf-8") NIL NIL "QUOTED-PRINTABLE" 871 27 NIL NIL NIL)
(
("TEXT" "HTML" ("CHARSET" "utf-8") NIL NIL "QUOTED-PRINTABLE" 2275 29 NIL NIL NIL)
("APPLICATION" "VND.OASIS.OPENDOCUMENT.TEXT" ("NAME" "Ethische Problemfelder.odt") NIL NIL "BASE64" 875794 NIL ("ATTACHMENT" ("FILENAME" "Ethische Problemfelder.odt")) NIL)
("TEXT" "HTML" ("CHARSET" "utf-8") NIL NIL "7BIT" 92 0 NIL NIL NIL) "MIXED" ("BOUNDARY" "Apple-Mail-4-784936864") NIL NIL
) "ALTERNATIVE" ("BOUNDARY" "Apple-Mail-3-784936862") NIL NIL
)'''
def pattern_dispatch(patterns_and_actions, source):
regex = re.compile('|'.join('(%s)' % r for r, _ in patterns_and_actions))
actions = [a for _, a in patterns_and_actions]
i = 0
for match in iter(lambda: regex.match(source, i), None):
actions[match.lastindex - 1](match.group())
i = match.end()
return i
def parse(source):
stack = [[]]
pattern_dispatch(
[
(r'\(', lambda _: stack.append(list())),
(r'\)', lambda _: stack[-2].append(tuple(stack.pop()))),
(r'NIL', lambda _: stack[-1].append(None)),
(r'[0-9]+', lambda t: stack[-1].append(int(t))),
(r'"[^"]*"', lambda t: stack[-1].append(t[1:-1])),
(r'\s+', lambda _: None),
],
source
)
return stack[0][0]
def main():
pprint(parse(SOURCE))
Re: Strings zu Tuple über ( und )
Verfasst: Montag 21. März 2011, 19:24
von Hyperion
Die Idee, die Pattern mit den Funktionen zu kombinieren gefällt mir da sehr gut! Ich hatte da auch überlegt, bin aber auf die nahe liegende Lösung (den RegExp erst später komplett zusammenzubauen) nicht gekommen. Damit wird der auch leichter wartbar bzw. überschaubar. Ich habe da auch schon irgend wie an den Weg aus pygments gedacht, wie die Lexer konstruieren, aber danke für Deinen Code, der mir da jetzt die Augen öffnet
