Seite 1 von 1
regex / finden und ersetzen durch unterschiedliche strings
Verfasst: Freitag 21. September 2007, 18:11
von mmg
hi,
ich hänge da an einer sache, bei der ich vielleicht nur einen kleinen tritt in die richtige richtung brauche...
quelltext:
Code: Alles auswählen
def imageparser(text):
try:
p = re.compile( ':IMAGE:(?P<photo_id>.*?):(?P<photosize>.*?):(?P<css_class>.*?):' )
m = p.search(text)
photo = Photo.objects.get(pk=m.group('photo_id'))
url = photo._get_SIZE_url(m.group('photosize'))
text = p.sub(r'<img class="\g<css_class>" src="%s">' % url, text)
return text
except:
return text
ich habe eine funktion, der ich einen text übergebe, und die aus diesem text mittels regex bestimmte ersetzungen vornimmt. so weit, so gut.
wenn im text also
vorkommt, dann sollen die einzelnen bestandteile herausgelöst und basierend auf diesen bestandteilen dann eben ersetzungen vorgenommen werden.
meine funktion von oben findet zwar alle vorkommenden strings, ersetzt werden sie aber nur durch das ergebnis der ersten ersetzung.
ich glaub ich seh den wald vor lauter bäumen nicht...
danke und grüße,
marco
Verfasst: Freitag 21. September 2007, 18:59
von BlackJack
Der Quelltext macht genau was Du beschreibst, mit ``p.search(text)`` wird das erste Vorkommen gesucht, daraus eine Ersetzungszeichenkette gebastelt und dann mit ``re.sub`` diese eine, feste Zeichenkette für alle Vorkommen des Musters eingesetzt.
Man kann `sub()` auch eine Funktion als erstes Argument übergeben, die ein Match-Objekt bekommt und eine Zeichenkette zurückgeben muss. Die wird dann für jeden Treffer mit dem entsprechenden Match-Objekt aufgerufen.
Verfasst: Freitag 21. September 2007, 20:03
von mmg
danke für den tipp. allerdings wird meinen tests zufolge die funktion auch nur das allererste mal aufgerufen und das resultat daraus für alle weiteren ersetzungen genommen.
die einzige methode bei der das zuverlässig funktioniert sind regex-groups, die ich im replacement-string verwende, die werden bei jedem durchlauf zuverlässig ersetzt.
aber ich habe eben nicht alle werte zur hand, sondern muss manche davon erst irgendwo her nehmen
.
grüße,
marco
Verfasst: Freitag 21. September 2007, 20:31
von BlackJack
Dann hast Du bei denen Tests etwas falsch gemacht. Die Funktion wird für *jeden* Treffer aufgerufen.
Verfasst: Freitag 21. September 2007, 23:26
von mmg
ja, sieht ganz danach aus, irgendetwas habe ich wahrscheinlich übersehen. ich habe extra meine tests jetzt noch mal wiederholt, komme aber zum gleichen ergebnis...
quälcode:
Code: Alles auswählen
import re
def imagereplacer(m):
try:
(phid, url, phcss) = m.groups()
return r'img class="%s" src="%s"' % (phcss, url)
except:
return ""
def imageparser(text):
try:
p = re.compile( ':IMAGE:(?P<photo_id>.*?):(?P<photosize>.*?):(?P<css_class>.*?):' )
m = p.search(text)
text = p.sub(imagereplacer(m), text)
return text
except:
return text
print imageparser("""
ein text
1. auftreten:
:IMAGE:123:small:left:
2. auftreten:
:IMAGE:234:big:right:
und noch ein text
""")
und das erzeugt bei mir folgende ausgabe:
Code: Alles auswählen
>c:\python25\pythonw -u "regextest.py"
ein text
1. auftreten:
img class="left" src="small"
2. auftreten:
img class="left" src="small"
und noch ein text
>Exit code: 0
noch eine idee für mich?
danke und grüße,
marco
Verfasst: Freitag 21. September 2007, 23:49
von poker
Hi,
schnell zusammengehackt und nicht optimiert.
Code: Alles auswählen
import re
def imagereplacer(m):
try:
phid, url, phcss, char = m.groups()
return r'img class="%s" src="%s"' % (phcss, url)
except:
return ""
def imageparser(text):
result = []
char_stack = []
to_stack = char_stack.append
to_result = result.append
p = re.compile(':IMAGE:(.*?):(.*?):(.*?):|(.)(?su)')
for m in p.finditer(text):
if m.groups()[3] is not None:
to_stack(m.groups()[3])
else:
if char_stack:
to_result("".join(char_stack))
to_result(imagereplacer(m))
return "".join(result)
print imageparser("""
ein text
1. auftreten:
:IMAGE:123:small:left:
2. auftreten:
:IMAGE:234:big:right:
und noch ein text
""")
Code: Alles auswählen
ein text
1. auftreten:
img class="left" src="small"
ein text
1. auftreten:
2. auftreten:
img class="right" src="big"
mfg
Verfasst: Samstag 22. September 2007, 00:11
von poker
Hi, eine bessere Lösung. Sollte flotter laufen
Code: Alles auswählen
import re
_image_re = re.compile(r':IMAGE:(.*?):(.*?):(.*?):')
def image_parser(text):
rv = []
last_pos = 0
for m in _image_re.finditer(text):
phid, url, phcss = m.groups()
txt = text[last_pos:m.start()]
if txt:
rv.append(txt)
last_pos = m.end()
rv.append(r'img class="%s" src="%s"' %(phcss, url))
return "".join(rv)
BTW: Das kompilieren des Patterns in der Funktion bringt keinerlei Geschwindigkeitsvorteil, weil es ja bei jedem Funktionsaufruf gemacht wird. Daher außerhalb der Funktion ausgelagert.
BTW2: Falls die id nicht benötigt wird, kann man gleich
schreiben und kann dann ``url, phcss = m.groups()`` statt ``phid, url, phcss = m.groups()`` schreiben.
mfg
P.S.: Musst aber teste ob alle fälle berücksichtigt werden.
EDIT:
Nimm lieber die regexe
, dann hast du keine blanks drine wenn z.B.
im text vorkommt
Also statt
kommt dann korrekt das raus:
Verfasst: Samstag 22. September 2007, 08:01
von BlackJack
@mmg: Du musst die *Funktion* als Argument übergeben. Was Du da machst ist wieder genau das selbe wie vorher. Du suchst immer noch selbst mit `search()` nach dem ersten Treffer und setzt den dann für alle ein. Einfach *nur die Funktion* übergeben!
Code: Alles auswählen
import re
def imagereplacer(m):
(phid, url, phcss) = m.groups()
return 'img class="%s" src="%s"' % (phcss, url)
def imageparser(text):
image_re = re.compile(':IMAGE:(?P<photo_id>.*?)'
':(?P<photosize>.*?)'
':(?P<css_class>.*?):')
return image_re.sub(imagereplacer, text)
print imageparser("""
ein text
1. auftreten:
:IMAGE:123:small:left:
2. auftreten:
:IMAGE:234:big:right:
und noch ein text
""")
Dann muss man auch nicht soviel selbst tun wie in poker's Lösung.
Verfasst: Samstag 22. September 2007, 10:23
von mmg
danke euch beiden, funktioniert jetzt problemlos.
grüße,
marco