Seite 1 von 1
Einen String parsen
Verfasst: Sonntag 1. Januar 2006, 11:13
von mitsuhiko
Es gibt wiedermal was zu Parsen und mir fehlt da irgendwo der Anfang:
Code: Alles auswählen
replace "Hello" "he|he hehe" | replace '$NAME$' user.username | addslashes
Soll zu der Datenstruktur werden:
Code: Alles auswählen
[['replace', '"Hello"', '"he|he hehe"'], ['replace', "'$NAME$', 'user.username'], ['addslashes']]
Jemand eine Idee? Innerhalb der Zeichenketten soll man auch mit einem Backslash escapen können, folgedem wird das wohl mit einer Regex nicht wirklich funktionieren.
Verfasst: Sonntag 1. Januar 2006, 12:51
von ProgChild
Wir wäre es zum Anfang mit
Code: Alles auswählen
s = "replace \"Hello\" \"he|he hehe\" | replace '$NAME$' user.username | addslashes".split()
print s
res=[]
tmp=[]
for e in s:
if e == '|':
res.append(tmp)
tmp=[]
else:
tmp.append(e)
print res
Jetzt solltest du das split noch durch eine RegEx ersetzten, das die Anführungszeichenberücksichtig...
Verfasst: Sonntag 1. Januar 2006, 12:56
von mitsuhiko
ProgChild hat geschrieben:
Jetzt solltest du das split noch durch eine RegEx ersetzten, das die Anführungszeichenberücksichtig...
Damit verliere ich aber die Leerzeichen in den Strings.

Verfasst: Sonntag 1. Januar 2006, 13:01
von ProgChild
blackbird hat geschrieben:Damit verliere ich aber die Leerzeichen in den Strings.

Das solltest du mit der RegEx berücksichtigen...
Verfasst: Sonntag 1. Januar 2006, 13:17
von ProgChild
So...
Das is doch net so schwer...
Code: Alles auswählen
import re
s = "replace \"Hello\" \"he|he hehe\" | replace '$NAME$' user.username | addslashes"
items = re.compile('".*"|\w+|\|').findall(s)
res=[]
tmp=[]
for e in items:
if e == '|':
res.append(tmp)
tmp=[]
else:
tmp.append(e)
print res
Verfasst: Sonntag 1. Januar 2006, 13:45
von mitsuhiko
Funktinoiert leider nicht. zwischen den Pipe Symbolen müssen übrigens keine leerzeichen vorkommen, was die Sache nicht gerade einfacher macht.
Verfasst: Sonntag 1. Januar 2006, 13:57
von ProgChild
blackbird hat geschrieben:Funktinoiert leider nicht. zwischen den Pipe Symbolen müssen übrigens keine leerzeichen vorkommen, was die Sache nicht gerade einfacher macht.
War noch ein kleiner Fehler drinn, aber sonst klappts. Wenn du mir nicht schreibst, wass nich funktionier, dann kann ich dir nicht helfen. In dem Programm von mir müssen außerdem auch keine Whitespaces vor, oder nach dem | Sybol sein.
Code: Alles auswählen
import re
s = "replace "Hello" "he|he hehe" | replace '$NAME$' user.username | addslashes"
items = re.compile('".*?"|[\w|$|\.]+|\|').findall(s)
res=[]
tmp=[]
for e in items:
if e == '|':
res.append(tmp)
tmp=[]
else:
tmp.append(e)
res.append(tmp)
print res
Das Resultat:
Code: Alles auswählen
> python whitespace_parse.py
[['replace', '"Hello"', '"he|he hehe"'], ['replace', '$NAME$', 'user.username'], ['addslashes']]
Verfasst: Sonntag 1. Januar 2006, 14:03
von mitsuhiko
ProgChild hat geschrieben:blackbird hat geschrieben:Funktinoiert leider nicht. zwischen den Pipe Symbolen müssen übrigens keine leerzeichen vorkommen, was die Sache nicht gerade einfacher macht.
War noch ein kleiner Fehler drinn, aber sonst klappts. Wenn du mir nicht schreibst, wass nich funktionier, dann kann ich dir nicht helfen.
Ausgabe:
Code: Alles auswählen
[['replace', '"Hello"', '"he|he hehe"'], ['replace', 'NAME', 'user', 'username']]
Ist nich das, was rauskommen soll.
Verfasst: Sonntag 1. Januar 2006, 14:04
von ProgChild
blackbird hat geschrieben:Ist nich das, was rauskommen soll.
Ich habs noch mal überarbeitet. Außerdem ist das nur ein Denkanstoß für dich, den du weiter ausbauen sollst.

Verfasst: Sonntag 1. Januar 2006, 14:25
von mitsuhiko
ProgChild hat geschrieben:blackbird hat geschrieben:Ist nich das, was rauskommen soll.
Ich habs noch mal überarbeitet. Außerdem ist das nur ein Denkanstoß für dich, den du weiter ausbauen sollst.


Danke ich weiß. Aber nach dem System komm ich nicht weit. Mein aktueller Versuch ist das ganze Zeichen für Zeichen durchzugehen und in Token einzuteilen. Ist nur verdammt langsam und 300 Zeilen lang.
Verfasst: Sonntag 1. Januar 2006, 15:31
von mitsuhiko
So. Meine aktuelle Lösung ist das hier:
Code: Alles auswählen
# -*- coding: utf-8 -*-
"""
Filter Parser
=============
source:
replace "Hello" "he|he hehe" | replace '$NAME$' user.username
result:
[['replace', '"Hello"', '"he|he hehe"'], ['replace', "'$NAME$'", 'user.username']]
"""
TOKEN_CDATA = 0
TOKEN_DOUBLE_QUOTED_STRING = 1
TOKEN_SINGLE_QUOTED_STRING = 2
TOKEN_DOUBLE_QUOTED_BACKSLASH = 3
TOKEN_SINGLE_QUOTED_BACKSLASH = 4
class EmptyTokenException(Exception): pass
class FilterLexer(object):
def __init__(self):
self._buffer = []
self._bufpos = 0
self._state = TOKEN_CDATA
self._valbuf = ''
self._tmpdata = []
self.data = []
def feed(self, data):
self._buffer.append(data)
try:
self.lex()
except EmptyTokenException:
pass
def finish(self):
self.feed('|')
def pop(self):
while self._buffer and self._bufpos >= len(self._buffer[0]):
del self._buffer[0]
self._bufpos = 0
if not self._buffer:
raise EmptyTokenException
rv = self._buffer[0][self._bufpos]
self._bufpos += 1
return rv
def lex(self):
while True:
if self._state == TOKEN_CDATA:
while True:
data = self.pop()
if data == '|':
self.handle_token(TOKEN_CDATA, self._valbuf)
self.handle_switch()
self._valbuf = ''
elif data in ' \t\r\n':
self.handle_token(TOKEN_CDATA, self._valbuf)
self._valbuf = ''
elif data == '"':
self.handle_token(TOKEN_CDATA, self._valbuf)
self._state = TOKEN_DOUBLE_QUOTED_STRING
self._valbuf = ''
break
elif data == "'":
self.handle_token(TOKEN_CDATA, self._valbuf)
self._state = TOKEN_SINGLE_QUOTED_STRING
self._valbuf = ''
break
else:
self._valbuf += data
if self._state == TOKEN_DOUBLE_QUOTED_STRING:
while True:
data = self.pop()
if data == '\\':
self._state = TOKEN_DOUBLE_QUOTED_BACHSLASH
break
elif data == '"':
self.handle_token(TOKEN_DOUBLE_QUOTED_STRING, self._valbuf)
self._state = TOKEN_CDATA
self._valbuf = ''
break
else:
self._valbuf += data
if self._state == TOKEN_SINGLE_QUOTED_STRING:
while True:
data = self.pop()
if data == '\\':
self._state = TOKEN_SINGLE_QUOTED_BACHSLASH
break
elif data == "'":
self.handle_token(TOKEN_SINGLE_QUOTED_STRING, self._valbuf)
self._state = TOKEN_CDATA
self._valbuf = ''
break
else:
self._valbuf += data
if self._state == TOKEN_DOUBLE_QUOTED_BACKSLASH:
self._valbuf += self.pop()
self._state = TOKEN_DOUBLE_QUOTED_STRING
if self._state == TOKEN_SINGLE_QUOTED_BACKSLASH:
self._valbuf += self.pop()
self._state = TOKEN_SINGLE_QUOTED_STRING
def handle_token(self, token_type, data):
if token_type == TOKEN_CDATA and data:
self._tmpdata.append(data)
elif token_type == TOKEN_SINGLE_QUOTED_STRING:
self._tmpdata.append('\'%s\'' % data)
elif token_type == TOKEN_DOUBLE_QUOTED_STRING:
self._tmpdata.append('"%s"' % data)
def handle_switch(self):
self.data.append(self._tmpdata)
self._tmpdata = []
def parse_filter(filterline):
lexer = FilterLexer()
lexer.feed(filterline)
lexer.finish()
return lexer.data
print parse_filter('replace "Hello" "he|he hehe" | replace \'$NAME\' user.username')
Aber wie gesagt. Langsam ist.
Verfasst: Sonntag 1. Januar 2006, 16:46
von XT@ngel
Hi blackbird,
Woher kommt dieser string:
Code: Alles auswählen
replace "Hello" "he|he hehe" | replace '$NAME$' user.username | addslashes
Ich frag mich gerade ob das replace und addslashes auch eine Funktion haben. Oder sind nur die | entscheidend die sich nicht zwischen zwei " befinden?
Ist die Länge vorgegeben also
Also drei "Felder"?
Lass mal ein paar Infos springen
MfG
Andreas
Verfasst: Sonntag 1. Januar 2006, 17:10
von mawe
Hi!
Vielleicht so?
Code: Alles auswählen
s = '''replace "Hello" "he|he hehe" | replace '$NAME$' user.username | addslashes'''
a = [[]]
quoted = False
tmp = ""
for sign in s:
if sign == '"': quoted = not quoted
if sign == '|' and not quoted:
a.append([])
elif sign == ' ' and not quoted:
if tmp:
a[-1].append(tmp)
tmp = ""
else:
tmp += sign
a[-1].append(tmp)
Gruß, mawe
Verfasst: Sonntag 1. Januar 2006, 18:52
von mitsuhiko
XT@ngel hat geschrieben:Hi blackbird,
Woher kommt dieser string:
Code: Alles auswählen
replace "Hello" "he|he hehe" | replace '$NAME$' user.username | addslashes
Ich frag mich gerade ob das replace und addslashes auch eine Funktion haben. Oder sind nur die | entscheidend die sich nicht zwischen zwei " befinden?
Klar ist das mit einer Funktion verbunden

Das ganze ist das Filtersystem von Jinja, der Parser findet sich atm hier:
http://wsgiarea.pocoo.org/trac/browser/ ... rparser.py
Die Pipe ist einfach zum weiterschicken an die nächste Funktion gedacht. Man kann dann im Template sowas machen:
@mawe: schaut gut aus, aber ein handling für einfache gequotete Strings ist nicht dabei

Verfasst: Sonntag 1. Januar 2006, 22:26
von BlackJack
Hilft das `shlex` Modul eventuell beim "Tokenizen"?
Verfasst: Sonntag 1. Januar 2006, 23:05
von mitsuhiko
BlackJack hat geschrieben:Hilft das `shlex` Modul eventuell beim "Tokenizen"?
argh. so einfach. Wiedermal die Batterien übersprungen. Das ist wirklich was Feines. Blöderweise fehlen mir die dazugehörigen Quotes wodurch ich nicht rausfinden kann, ob das jetzt eine Stringkonstante oder eine Variable ist
