Regular expressions: Ändern der Reihenfolge mit VAR Teil!

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
Cleo
User
Beiträge: 4
Registriert: Freitag 29. Mai 2009, 16:48

Hallo zusammen,

ich verwende Python noch nicht so lange

Ich möchte eine Textdatei mit einem Pythonscript bearbeiten um das Format zu ändern, was bisher auch gut funktioniert hat. Nun stehe ich vor einem Problem, das ich bisher leider nicht lösen konnte.

Der größte Teil des eigentlichen Problems war feststehende Begriffe wie TEXT_A durch TEXT_B zu ersetzten. Das habe ich mit Hilfe von regular expressions gelöst.

Code: Alles auswählen

fh = open('DOC_A','r')
stuff = fh.read()
fh.close()
new_stuff = re.sub('TEXT_A','TEXT_B',stuff)
fh = open('DOC_B','w')
fh.write(new_stuff)
fh.close()
Nun habe ich aber das Problem, dass ich an einer Stelle zusätzlich erst die Reihenfolge vertauschen möchte, sprich
TEXT_A(a) TEXT_A(b) durch TEXT_B(b) TEXT_B(a)
und zweitens sowohl TEXT_A(a) und TEXT_A(b) enthalten einen variablen Teil, der auch erhalten bleiben soll, sprich
XAXAXA<variabler Teil>XAXAXA.

Beides zusammen soll dann als Ergebnis ergeben:
ursprünglicher Text

XAaXAaXAa<variabler Teil A>XAaXAaXAa
XAbXAbXAb<variabler Teil B>XAbXAbXAb


veränderter Text

XBbXBbXBb<variabler Text identisch zu _Ab>XBbXBbXBb
XBaXBaXBa<variabler Text identisch zu _Aa>XBaXBaXBa

Ich habe bisher versucht wildcards einzubauen oder Variablen zu definieren ... war aber eher erfolglos damit (in der Ausgabe der Variablen im Ersetze-Teil der regular expression).

Habe auch versucht nach Schlagwörtern wie pattern, sequence und strings zu suchen ... habe aber nichts entdeckt was meinem Problem nahe kam.

Also falls jemand mir einen Hinweis geben könnte wie ich das Problem lösen kann oder mit welcher Art von Konstruktion man das ganze geschickt angehen könnte wäre ich echt dankbar :)

Gruss Cleo
problembär

Hmmm, so?

Code: Alles auswählen

#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-

import re

a = ["XAaXAaXAa<variabler Teil A>XAaXAaXAa",
     "XAbXAbXAb<variabler Teil B>XAbXAbXAb"]

a[0] = a[0].replace("XAa", "XBb")
a[1] = a[1].replace("XAb", "XBa")

patobj = re.compile("<.*>")

matchobj = patobj.search(a[0])
if matchobj is not None:
    substr0 = matchobj.group()

matchobj = patobj.search(a[1])
if matchobj is not None:
    substr1 = matchobj.group()

a[0] = a[0].replace(substr0, substr1)
a[1] = a[1].replace(substr1, substr0)

for i in a:
    print i
Gruß
Benutzeravatar
martin101986
User
Beiträge: 85
Registriert: Montag 3. Dezember 2007, 19:15
Wohnort: Steiermark, Österreich

Hallo,

erstmal willkommen im Forum. Mit Regular Expressions warst du schon auf dem richtigen Weg.

Hier mein Lösungsvorschlag:

Code: Alles auswählen


import re

old_text = 'XAaXAaXAa<text>XAaXAaXAa'
old_text2 = 'XAbXAbXAb<nochmehrtext>XAbXAbXAb'
pattern = re.compile(r'\w+(<[\w|\s]*>)\w+')

new_text = pattern.sub(r'XBaXBaXBa\1XBaXBaXBa', old_text)
                            
new_text2 = pattern.sub(r'XBbXBbXBb\1XBbXBbXBb', old_text2)
	
print new_text, new_text2

Mfg
Martin
Cleo
User
Beiträge: 4
Registriert: Freitag 29. Mai 2009, 16:48

hallo zusammen,
vielen, vielen Dank für eure Antworten! Erst mal vorweg Entschuldigung, dass es etwas länger gedauert hat mit dem Antworten ... aber da ich noch nicht so geübt bin mit Python, musste ich erst mal viel lesen um euch hoffentlich unnötige Fragen zu ersparen.
Auch wenn ich die Lsg lleider immer noch nicht habe, habe ich schon wieder eine Menge dazugelernt :)


@ problembär : ich muss offen zugeben ich habe es versucht, aber deinen Lösungsvorschlag nicht wirklich verstanden ... was aber glaube ich noch eher an meinem (noch) eingeschränkten Pythonverständnis liegt, als an deinem Stückchen Code :?
Wenn ich es versuche an einem Minimalbsp. laufen zu lassen, um zu schauen was es macht bekomme ich die Fehlermeldung:

NameError: name 'substr1' is not defined

@martin : bei dir bin ich etwas weiter gekommen, bin aber leider noch nicht ganz am Ziel.

hier mal das Minimalbeispiel mit dem ich versucht habe das Programm zu optimieren:

Hallo sie fahren gerne einen gruenen Hund .
Hallo sie driven gerne einen gelben Hund .
Hallo sie flitzen gerne einen blauen Hund .

FIX [XAa1 var1 XAa2] [XAb1 var2 XAb2] FIX

Ziel ist es folgenden (wenn auch zugegebenermaßen sinnfreien) Text herauszubekommen.

Hallo viele gruenen Hasen du fahren ungerne .
Hallo viele gelben Hasen du driven ungerne .
Hallo viele blauen Hasen du flitzen ungerne .


FIX [XBb1 var2 XBb2] [XBa1 var1 XBa2] FIX

So wenn ich das Programm jetzt anpasse (siehe Code) das es einen Textfile aufruft mit dem Ausgangstext und das folgende Skript drüber laufen lasse und in ein neues Dokument schreibe erhalte ich folgendes Ergebnis:

Code: Alles auswählen

 #!/usr/bin/env python

import re

fh = open('cleo.txt','r')
stuff = fh.read()
fh.close()

old_text = 'sie /* gerne '
old_text2 = 'einen /* Hund '
pattern = re.compile(r'\w+(<[\w|\s]*>)\w+')

new_text = pattern.sub(r'du\1ungerne ', old_text,)
new_text2 = pattern.sub(r'viele\1Hasen', old_text2)

fh = open('cleo.txtt','w')
fh.write(new_text2)
fh.write(new_text)
fh.close() 
Ausgabe (in cleo.txtt): einen /* Hund sie /* gerne

1. Mit /* habe ich versucht den variablen Text zu fischen, habe verschiedenstes ausprobiert (<.*>, *, "*",...) habe aber immer nur die eins zu eins Ausgabe wie in diesem Bsp. oder ein Kästchen erhalten.
Der Variable Teil ist leider immer unterschiedlich, an der Stelle muss ich irgendwie eine Wildcard verwenden.

2. Das Skript hat zwar die Reihenfolge gedreht, aber die vom alten Text. Wenn ich allerdings die Reihenfolge im pattern.sub umgedreh, dann klappts (zumindest die Reihenfolge).

Code: Alles auswählen

new_text = pattern.sub(old_text,r'du\1ungern ')
new_text2 = pattern.sub(old_text2,r'viele\1Hasen ')
Ausgabe: viele\1Hasen du\1ungern

3. Es gibt mir nie den vollständigen Text aus.
Bisher ist das immer geschehen indem ich nach der Substitution noch ",stuff" hatte, aber im pattern.sub scheint es nach diesen Regeln nicht zu funktionieren.

Code: Alles auswählen

new_stuff = re.sub('TEXT_A','TEXT_B',stuff)
entsprechend

Code: Alles auswählen

new_text = pattern.sub(r'du\1ungerne ', old_text,stuff)
new_text2 = pattern.sub(r'viele\1Hasen', old_text2,stuff)
Die Fehlermeldung lautet dann:
TypeError: an integer is required

Ich habe leider aber nicht herausgefunden nach welchen Regeln es funktioniert.


So, ist jetzt leider etwas mehr Text geworden, hoffe es hält sich noch im Rahmen. Ich hoffe das ich nicht einfach nur eine triviale Lsg übersehen habe und das ihr mir vielleicht noch einmal ein bisschen auf die Sprünge helfen könnt :)

Vielen lieben Dank auf jeden Fall schon mal im Voraus für eure Hilfe.

MfG Cleo
Benutzeravatar
martin101986
User
Beiträge: 85
Registriert: Montag 3. Dezember 2007, 19:15
Wohnort: Steiermark, Österreich

Hallo,

da habe ich dich Missverstanden. Ich bin davon ausgegangen dass der Text wirklich im Format
XAaXAaXAa<variabler Teil A>XAaXAaXAa
vorliegt und habe nach diesem die Regular Expression geschrieben.

Daher findet re.sub nun auch nichts mehr und gibt dir den String unverändert zurück.

So funktionierts, allerdings nur mit 7 Wörter:

Code: Alles auswählen

pattern = re.compile(r'\w+\s\w+\s([\w]+)\s\w+\s\w+\s([\w]+)\s\w+')

text = pattern.sub(r'Hallo viele \2 Hasen du \1 ungerne', 'Hallo sie fahren gerne einen gruenen Hund.')
Ergibt: Hallo viele gruenen Hasen du fahren ungerne .

Kann man sicher noch verbessern, bin dafür leider selber zu wenig in re's geübt.
Wozu willst du diesen Text ersetzen lassen, ich verstehe die Sinnhaftigkeit nicht wirklich dahinter. Was willst du damit erreichen?

Grüße
Martin
problembär

Oh Mann,

wer denkt sich eigentlich so'n krankes Problem aus :shock:?
Hier ein Ansatz:

Code: Alles auswählen

#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-

a = ["Hallo sie fahren gerne einen gruenen Hund .",
     "Hallo sie driven gerne einen gelben Hund .",
     "Hallo sie flitzen gerne einen blauen Hund ."]

b = a[0].split(" ")

fix1 = b[0]
b.remove(fix1)

fix2 = b.pop()

XAa1 = b[0]
b.remove(XAa1)

XAb2 = b.pop()

var = b
print var

# XAa2 = "gerne"
# XAb1 = "einen"

XBb1 = "viele"
XBb2 = "Hasen"
XBa1 = "du"
XBa2 = "ungerne"
Leider kann ich XAa2 und Xab1 aber nicht aus den Strings oder aus meiner Liste var extrahieren, weil die in der Mitte liegen und nicht klar ist, bis wo var1 und var2 gehen.

Wo kommen eigentlich die Daten für XBa1/2, XBb1/2 her?

Soweit.

Viel Spaß damit
Cleo
User
Beiträge: 4
Registriert: Freitag 29. Mai 2009, 16:48

Hui, danke für die schnellen Antworten.

Mmmh, die Beispielsätze waren von mir :? Ich gebe ja zu das sie etwas komisch sind, aber ich dachte sie verdeutlichen das Problem und zum Testen waren sie toll (versuche mir das nächste Mal bei meinem Bsp noch mehr Mühe zu geben).

ALso, ich habe ein etwas merkwürdiges Dokument, dass leider (aus historischen Gründen) aus den unterschiedlichsten Formaten besteht ... Latex, XML, HTML, ... (viele Köche verderben den Brei) und ich hätte es gerne in compilierfähigem Latexcode

Habe soweit alles gelöst bis auf:

<Section1 ID="xxx"><Heading> XXX </Heading> </Section1> (wohl XML code)

das ich gerne in folgenden Latex Code hätte

\section{XXX}
\label{xxx}

XXX und xxx sind die variablen Teile.

(wäre dann:
<Section1 = Fix --> \section{ [normales re.sub]
ID=" = XAa1 --> \label{ [XBa1]
xxx = var1 --> xxx
"> = XAa2 --> } [XBa2]
<Heading> = XAb1 --> Leerzeichen [XBb1]
XXX = var2 --> XXX
</Heading></Section1> = XAb2 --> } [XBb2] )


Die Einzelkomponenten zu ersetzen, war kein Thema. Aber ich brauche das \label erst NACH der Überschrift. Und prinzipiell sollte das möglich sein.

Das Dokument ist relativ groß (>50 Seiten), weswegen von Hand bearbeiten sich nicht anbietet, deswegen habe ich Python verwendet.

So, jetzt schau ich mir erst mal genauer an was ihr vorgeschlagen habt, dauert ja wie gesagt immer noch etwas länger bis ich das auseinanderklamüsert habe, vielleicht klappts ja dann auch :)

Das war erst mal nur die Erklärung für das "kranke" ;) Beispiel.
BlackJack

@Cleo: Also das konkrete Beispiel müsste sich mit diesem Muster und dieser Ersetzung lösen lassen:

Code: Alles auswählen

pattern = r'\<Section1\s+ID="(.*?)"\>\<Heading\>(.*?)\</Heading\>\s*\</Section1\>'
replacement = r'\section{\2}\n\label{sec:\1}'
Wobei XML mit regulären Ausdrücken zu parsen immer ein wenig unschön ist.
problembär

Ich würde DAS dann so machen:

Code: Alles auswählen

#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-

a = '<Section1 ID="xxx"><Heading> XXX </Heading> </Section1>'

b = a.split('"')
var1 = b[1]

b = a.split('>')
c = b[2].split('<')
var2 = c[0]
var2 = var2.strip()

a = "\section{" + var2 +"}\n"
a += "\label{" + var1 + "}"

print a
Oder habe ich schon wieder etwas mißverstanden ...

Gruß
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

BlackJack hat geschrieben:

Code: Alles auswählen

pattern = r'\<Section1\s+ID="(.*?)"\>\<Heading\>(.*?)\</Heading\>\s*\</Section1\>'
replacement = r'\section{\2}\n\label{sec:\1}'
was beudeutet denn das "sec" bei zugriff auf die erste gruppe?
http://www.kinderpornos.info
BlackJack

Aus Sicht von regulären Ausdrücken bedeutet das gar nichts. Das ist eine Konvention bei LaTeX, dass man den Marken ein Präfix verpasst, das den Typ angibt, also `sec:` für Abschnitte, `fig:` für Abbildungen, `lst:` für Listings usw.
Cleo
User
Beiträge: 4
Registriert: Freitag 29. Mai 2009, 16:48

... hat zwar wieder bei mir etwas länger gedauert ... aber die Antwort von BlackJack hat mich tatsächlich ans Ziel gebracht :) und mit ein bisschen üben und probieren konnte ich es sogar noch abwandeln, erweitern und umformen. Und ich glaube ich habe auch vom Verständnis wieder das eine oder andere dazugelernt.

Aber auf jeden Fall, vielen, vielen Dank an alle die sich hier über dieses Problem den Kopf zerbrochen haben!
Antworten