Search and replace

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
OlliD
User
Beiträge: 5
Registriert: Donnerstag 29. Januar 2009, 17:09
Kontaktdaten:

Hallo,

vielleicht in ich ja richtig in diesem Teil des Forums ;)

Also, ich habe ein S&R-Problem und dachte mir Python waere die richtige Sprache fuer eine schnelle Loesung. Ich habe mir ein Skript geschrieben, oder vielleicht besser ich dachte ich haette dies getan, womit ich eine Liste der Form [SUCHE_DIES, ERSETZE_HIERMIT] Zeilenweise einlese und dann in der Datei die ich als zweites Argument uebergebe nach SUCHE_DIES suche und es mit ERSETZE_HIERMIT ersetze. Doch leider klappt das nicht so ganz, vielmehr wird der Inhalt der ersten Datei in die Zweite uebertragen :(

Kann mir vielleicht jemand einen Tipp geben?

Viele Gruesse,
Olli

Code: Alles auswählen

#!/usr/bin/python
import os, sys
usage = "usage: %s File_with_predicates annotation_file" %        os.path.basename(sys.argv[0])

if len(sys.argv) < 2:
	print usage

else:
	#print sys.argv[1]
	input = sys.stdin
	output = sys.stdout
	#print "Es %s args " %len(sys.argv)
	if len(sys.argv) == 3:
		input = open(sys.argv[1], 'r')
		#stext = sys.argv[1]
		#rtext = sys.argv[2]
		j = len(open(sys.argv[1]).readlines())
		print  j
		for line in input:
			sline = line.split(',')
			stext = sline[0].strip()
			print "searching for " + stext
			rtext = sline[1].strip()
			print "replacing with " + rtext
			output = open(sys.argv[2], 'w')
		        if len(sys.argv) > 2:
				output = open(sys.argv[2], 'w')
			for s in input:
                		output.write(s.replace(stext, rtext))
		
	input.close()
output.close()
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Code: Alles auswählen

infile = open("infile.txt")
outfile = open("outfile.txt", "w")
outfile.write(infile.read().replace("ersetz mich", "dadurch"))
infile.close()
outfile.close()
Edit: Die Verwendung von input als Bezeichner ist im übrigen keine gute Idee, weil es eine builtin-function ist.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Mit with ;)

Code: Alles auswählen

with open("infile.txt") as infile:
    with open("outfile.txt", "w") as outfile:
        for line in infile:
            outfile.write(line.replace("ersetz mich", "dadurch"))
lunar

Mit "contextlib.nested()" lässt sich da eine Einrückungsebene einsparen.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

lunar hat geschrieben:Mit "contextlib.nested()" lässt sich da eine Einrückungsebene einsparen.
Was es alles gibt.
OlliD
User
Beiträge: 5
Registriert: Donnerstag 29. Januar 2009, 17:09
Kontaktdaten:

Vielen Dank für die schnellen Antworten! Ich habe gleich mal versucht diesen Ansatz umzusetzen:

Code: Alles auswählen

with open("infile.txt") as infile:
    with open("outfile.txt", "w") as outfile:
        for line in infile:
            outfile.write(line.replace("ersetz mich", "dadurch"))
Musste aber leider feststellen, das es das erst ab Version 2.6 implementiert ist.. :( Hat noch jemand eine andere Idee?
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

with?

from __future__ import with_statement
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

OlliD hat geschrieben:Musste aber leider feststellen, das es das erst ab Version 2.6 implementiert ist.. :( Hat noch jemand eine andere Idee?
Ich habe doch eine "andere Idee" gepostet. Ist zwar nur die zweitbeste Lösung, aber funktioniert auch ohne with (und future-import).
lunar

numerix hat geschrieben:
OlliD hat geschrieben:Musste aber leider feststellen, das es das erst ab Version 2.6 implementiert ist.. :( Hat noch jemand eine andere Idee?
Ich habe doch eine "andere Idee" gepostet. Ist zwar nur die zweitbeste Lösung, aber funktioniert auch ohne with (und future-import).
Naja, try-finally fehlt noch, um die Datei sicher zu schließen.
OlliD
User
Beiträge: 5
Registriert: Donnerstag 29. Januar 2009, 17:09
Kontaktdaten:

Aber das ist auch erst ab 2.5 verfügbar, oder? Leider ist in unserem Volume bloß

Code: Alles auswählen

Python 2.4.3 (#2, Jul 31 2008, 21:56:52) 
installiert.. Ich sollte morgen mal den Admin fragen ob es aufwendig ist ein Update zu machen ..
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

lunar hat geschrieben:Naja, try-finally fehlt noch, um die Datei sicher zu schließen.
Okay, dann war es die drittbeste Lösung ...

@OlliD: Für meine Variante reicht Python 2.4 allemal.
OlliD
User
Beiträge: 5
Registriert: Donnerstag 29. Januar 2009, 17:09
Kontaktdaten:

Hallo noch mal,

ich habe dann mal etwas weiter gebastelt:

Code: Alles auswählen

#!/usr/bin/python
import os, sys

usage = "usage: %s File_with_predicates annotation_file" %        os.path.basename(sys.argv[0])

if len(sys.argv) < 2:
	print usage

else:
	#print sys.argv[1]
	infile = sys.stdin
	outfile = sys.stdout
	#print "Es %s args " %len(sys.argv)
	if len(sys.argv) == 3:
		#with open(sys.argc[1])as infile:
		#infile = open(sys.argv[1], 'r')
		#stext = sys.argv[1]
		#rtext = sys.argv[2]
		infile = open(sys.argv[1], 'r')
		outfile = open(sys.argv[2], 'w')
		j = len(open(sys.argv[1]).readlines())
		print  j
		n = 1 
		while n < j:
			line = infile.readline()
			sline = line.split(',')
			stext = sline[0].strip()
			print "searching for " + stext
			rtext = sline[1].strip()
			print "replacing with " + rtext
			i = len(open(sys.argv[2]).readlines())
			m = 1
			while m < i:
				replace_text = outfile.readline()
				if 'stext' in 'replace_text':
					outfile.write(replace_text.replace(stext, rtext))
					print "replacing " + rtext
				m += 1
			outfile.close
			n += 1
Aber aus irgendeinem Grund ist meine Zeildatei im Anschluss leer - ganz egal welchen Inhalt sie hat. Dabei soll er in der zweiten Schleife doch nur etwas geschrieben werden wenn er den Suchstring auch findet :(

Hiiiiiilfe !!
BlackJack

@OlliD: Hör mal bitte auf Indexe und ``while``-Schleifen zu benutzen und insbesondere ständig Dateien komplett einzulesen, nur um zu zählen, wieviele Zeilen enthalten sind.

Um Funktionen und Methoden *aufzurufen* braucht es Klammern. Du schliesst also keine der Dateien, die Du öffnest. Was Du tun solltest.

Bei `outfile` die `readline()`-Methode aufzurufen ist keine gute Idee. Du musst Dich schon entscheiden ob Du eine Datei einlesen oder schreiben möchtest. *Beides* auf *einer* Textdatei bringt in der Regel nur Probleme.

Wenn Du eine Datei zum Schreiben ('w') öffnest, wird der Inhalt gelöscht. Darum ist da auch nix mehr drin.
OlliD
User
Beiträge: 5
Registriert: Donnerstag 29. Januar 2009, 17:09
Kontaktdaten:

Hallo,

noch mal vielen Dank für eure Hilfe! Ich habe das Problem nun hoffentlich gelöst, der Code sieht so aus:

Code: Alles auswählen

#!/usr/bin/env python
import os, sys
usage = "usage: %s File_with_predicates annotation_file" %        os.path.basename(sys.argv[0])

if len(sys.argv) < 2:
        print usage
else:
        input = open(sys.argv[1], 'r')
        mapping = {}
        for line in input:
                line = line.strip()
                predicates = line.split(" ")
                mapping[predicates[0]] = predicates[1]
        input.close()
        elanfile = open(sys.argv[2], 'r')
        outfile = open("elanfile"+"_mode",'w')
        for line in elanfile:
                for key in mapping.iterkeys():
                        where = line.find(key)
                        if where <> '0':
                                print key + " becomes " + mapping.get(key)
                                outline = line.replace(key, mapping.get(key))
                        else:
                                outline = line
                outfile.write(outline)
        elanfile.close()
        outfile.close()
print mapping
Ich habe es noch nicht richtig getestet, glaube aber das es funktioniert.

Vielen Dank,
OlliD
BlackJack

Sieht so aus, als könnte es fast funktionieren. Zwei Punkte, die mir beim drüberlesen aufgefallen sind:

1. Der Test auf die Länge der Argumentliste stimmt nicht, weil zwei Elemente nicht ausreichen um mit dem Index 2 auf das *dritte* Element in der Liste zuzugreifen.

2. Wenn die Anzahl der Argumente zu klein ist, wird `mapping` nicht definiert und die letzte Zeile führt zu einem `NameError`.

Ansonsten könnte man das alles noch etwas vereinfachen. Einlesen in ein Dictionary ginge auch so:

Code: Alles auswählen

    predicate_lines = open(sys.argv[1], 'r')
    replacements = dict(line.strip().split(' ') for line in predicate_lines)
    predicate_lines.close()
Allerdings braucht man hier kein Dictionary, eine Liste mit Tupeln/Listen würde auch gehen. Und vor allem bleibt da die Reihenfolge der Einträge aus der ersten Datei erhalten, was bei Ersetzungen durchaus einen Unterschied machen kann.

Die mittlere Zeile im letzten Beispiel würde dann so lauten:

Code: Alles auswählen

    replacements = [line.strip().split(' ') for line in predicate_lines]
Das Ersetzen ist viel zu kompliziert gelöst. `replace()` sucht den alten Text und ersetzt ihn durch den neuen. Es gibt keinen Grund vorher selber nach dem alten Text zu suchen. Das verbraucht einfach nur unnötig Zeit. Wenn es Dir um die ``print``-Ausgabe geht, dann Vergleiche einfach die Zeilen vor und nach dem Ersetzen, das ist potentiell schneller.

Ansonsten reicht:

Code: Alles auswählen

    for line in elanfile:
        for old, new in replacements:
            line = line.replace(old, new)
        outfile.write(line)
Antworten