Wie suche und ersetze ich Text in einer Datei?

212

Wie suche und ersetze ich Text in einer Datei mit Python 3?

Hier ist mein Code:

import os
import sys
import fileinput

print ("Text to search for:")
textToSearch = input( "> " )

print ("Text to replace it with:")
textToReplace = input( "> " )

print ("File to perform Search-Replace on:")
fileToSearch  = input( "> " )
#fileToSearch = 'D:\dummy1.txt'

tempFile = open( fileToSearch, 'r+' )

for line in fileinput.input( fileToSearch ):
    if textToSearch in line :
        print('Match Found')
    else:
        print('Match Not Found!!')
    tempFile.write( line.replace( textToSearch, textToReplace ) )
tempFile.close()


input( '\n\n Press Enter to exit...' )

Eingabedatei:

hi this is abcd hi this is abcd
This is dummy text file.
This is how search and replace works abcd

Wenn ich 'ram' in der obigen Eingabedatei suche und durch 'abcd' ersetze, funktioniert das als Zauber. Aber wenn ich es umgekehrt mache, dh 'abcd' durch 'ram' ersetze, bleiben am Ende einige Junk-Charaktere übrig.

Ersetzen von 'abcd' durch 'ram'

hi this is ram hi this is ram
This is dummy text file.
This is how search and replace works rambcd
Shriram
quelle
Können Sie etwas genauer sein, wenn Sie sagen, dass am Ende noch einige Junk-Charaktere übrig sind? Was sehen Sie?
Burhan Khalid
Aktualisierte die Frage mit Ausgabe, was ich bekam.
Shriram

Antworten:

241

fileinputunterstützt bereits die Inplace-Bearbeitung. stdoutIn diesem Fall wird zur Datei umgeleitet :

#!/usr/bin/env python3
import fileinput

with fileinput.FileInput(filename, inplace=True, backup='.bak') as file:
    for line in file:
        print(line.replace(text_to_search, replacement_text), end='')
jfs
quelle
13
Was soll das end=''Argument tun?
egpbos
18
linehat bereits eine neue Zeile. endist standardmäßig eine neue Zeile, damit end=''die print()Funktion keine zusätzliche neue Zeile druckt
jfs
11
Verwenden Sie keinen Dateieingang! Schreiben Sie stattdessen den Code, um dies selbst zu tun. Das Umleiten von sys.stdout ist keine gute Idee, insbesondere wenn Sie es ohne einen Versuch tun. Endlich wie bei fileinput. Wenn eine Ausnahme ausgelöst wird, wird Ihr Standard möglicherweise nie wiederhergestellt.
Craigds
9
@craigds: falsch. fileinputist kein Werkzeug für alle Arbeitsplätze ( nichts ) , aber es gibt viele Fälle , in denen es ist das richtige Werkzeug zum Beispiel eines implementieren sed-ähnlichen Filter in Python. Verwenden Sie keinen Schraubenzieher, um Nägel zu schlagen.
JFS
5
Wenn Sie stdout aus irgendeinem Grund wirklich in Ihre Datei umleiten möchten, ist es nicht schwer, es besser zu machen als fileinputdies (im Grunde genommen verwenden Sie try..finallyoder einen Kontextmanager, um sicherzustellen, dass Sie stdout danach wieder auf den ursprünglichen Wert zurücksetzen). Der Quellcode für fileinputist ziemlich schrecklich und macht einige wirklich unsichere Dinge unter der Haube. Wenn es heute geschrieben worden wäre, bezweifle ich sehr, dass es es in die stdlib geschafft hätte.
Craigds
333

Wie von michaelb958 hervorgehoben, können Sie nicht durch Daten unterschiedlicher Länge ersetzen, da dadurch der Rest der Abschnitte fehl am Platz ist. Ich bin nicht einverstanden mit den anderen Postern, die vorschlagen, dass Sie aus einer Datei lesen und in eine andere schreiben. Stattdessen las ich die Datei in den Speicher, reparierte die Daten und schrieb sie dann in einem separaten Schritt in dieselbe Datei.

# Read in the file
with open('file.txt', 'r') as file :
  filedata = file.read()

# Replace the target string
filedata = filedata.replace('ram', 'abcd')

# Write the file out again
with open('file.txt', 'w') as file:
  file.write(filedata)

Es sei denn, Sie haben eine massive Datei zum Arbeiten, die zu groß ist, um auf einmal in den Speicher geladen zu werden, oder Sie sind besorgt über einen möglichen Datenverlust, wenn der Prozess während des zweiten Schritts, in dem Sie Daten in die Datei schreiben, unterbrochen wird.

Jack Aidley
quelle
5
with file = open(..):ist nicht gültig Python ( =), obwohl die Absicht klar ist. .replace()ändert die Zeichenfolge nicht (sie ist unveränderlich), daher müssen Sie den zurückgegebenen Wert verwenden. Auf jeden Fall kann der Code, der große Dateien unterstützt , noch einfacher sein, es sei denn, Sie müssen Text suchen und ersetzen, der mehrere Zeilen umfasst.
JFS
40
Sie haben ganz recht, und deshalb - Leute - sollten Sie Ihren Code testen, bevor Sie sich im Internet
blamieren
19
@ JonasStein: Nein, das sollte es nicht. Die withAnweisung schließt die Datei automatisch am Ende des Anweisungsblocks.
Jack Aidley
2
@ JackAidley das ist interessant. Vielen Dank für die Erklärung.
Jonas Stein
4
@JackAidley, weil es kurz, einfach, leicht zu verwenden und zu verstehen ist und ein echtes Problem anspricht, das viele Menschen haben (und daher viele Menschen suchen - und so Ihre Antwort finden).
Ben Barden
52

Wie Jack Aidley gepostet hatte und JF Sebastian darauf hinwies, wird dieser Code nicht funktionieren:

 # Read in the file
filedata = None
with file = open('file.txt', 'r') :
  filedata = file.read()

# Replace the target string
filedata.replace('ram', 'abcd')

# Write the file out again
with file = open('file.txt', 'w') :
  file.write(filedata)`

Aber dieser Code wird funktionieren (ich habe ihn getestet):

f = open(filein,'r')
filedata = f.read()
f.close()

newdata = filedata.replace("old data","new data")

f = open(fileout,'w')
f.write(newdata)
f.close()

Mit dieser Methode können filein und fileout dieselbe Datei sein, da Python 3.3 die Datei beim Öffnen zum Schreiben überschreibt.

Neamerjell
quelle
9
Ich glaube, der Unterschied liegt hier: Filedata.replace ('ram', 'abcd') Im Vergleich zu: newdata = Filedata.replace ("alte Daten", "neue Daten") Nichts mit der Anweisung "with" zu tun
Diegomanas
5
1. Warum sollten Sie with-statement entfernen ? 2. Wie in meiner Antwort angegeben, fileinputkann an Ort und Stelle funktionieren - es kann Daten in derselben Datei ersetzen (es verwendet intern eine temporäre Datei). Der Unterschied besteht darin, dass fileinputnicht die gesamte Datei in den Speicher geladen werden muss.
JFS
8
Nur um andere zu retten, die Jack Aidleys Antwort noch einmal wiederholen, wurde sie seit dieser Antwort korrigiert, sodass diese jetzt überflüssig ist (und aufgrund des Verlusts der saubereren withBlöcke minderwertig ist ).
Chris
46

Sie können den Austausch so durchführen

f1 = open('file1.txt', 'r')
f2 = open('file2.txt', 'w')
for line in f1:
    f2.write(line.replace('old_text', 'new_text'))
f1.close()
f2.close()
Jayram
quelle
7

Sie können auch verwenden pathlib.

from pathlib2 import Path
path = Path(file_to_search)
text = path.read_text()
text = text.replace(text_to_search, replacement_text)
path.write_text(text)
Yuya Takashina
quelle
Danke Yuya. Die obige Lösung hat gut funktioniert. Hinweis: Sie müssen zuerst eine Sicherungskopie Ihrer Originaldatei erstellen, da diese Ihre Originaldatei selbst ersetzt. Wenn Sie wiederholt Text ersetzen möchten, können Sie die letzten beiden Zeilen wie folgt hinzufügen. text = text.replace (text_to_search, replace_text) path.write_text (text)
Nages
3

Mit einem Single mit Block können Sie Ihren Text suchen und ersetzen:

with open('file.txt','r+') as f:
    filedata = f.read()
    filedata = filedata.replace('abc','xyz')
    f.truncate(0)
    f.write(filedata)
iknowitwasyoufredo
quelle
1
Sie haben seekden Anfang der Datei vergessen, bevor Sie sie geschrieben haben. truncatetut das nicht und so haben Sie Müll in der Datei.
ur.
2

Ihr Problem ergibt sich aus dem Lesen und Schreiben in dieselbe Datei. Anstatt Öffnung fileToSearchzum Schreiben, öffnen Sie eine tatsächliche temporäre Datei und dann , nachdem Sie fertig sind und geschlossen haben tempFile, verwenden , os.renameum die neue Datei über zu bewegen fileToSearch.

icktoofay
quelle
1
Freundliches FYI (zögern Sie nicht, die Antwort zu bearbeiten): Die Hauptursache ist nicht, dass die Mitte einer vorhandenen Datei verkürzt werden kann. Das heißt, wenn Sie nach 5 Zeichen suchen und durch 3 ersetzen, werden die ersten 3 Zeichen der 5 gesuchten Zeichen ersetzt. aber die anderen 2 können nicht entfernt werden, sie bleiben einfach dort. Die Lösung für temporäre Dateien entfernt diese "verbleibenden" Zeichen, indem sie gelöscht werden, anstatt sie in die temporäre Datei zu schreiben.
michaelb958 - GoFundMonica
2

(pip install python-util)

from pyutil import filereplace

filereplace("somefile.txt","abcd","ram")

Der zweite Parameter (das zu ersetzende Objekt, z. B. "abcd", kann auch ein regulärer Ausdruck sein)
ersetzt alle Vorkommen

MisterL2
quelle
Ich hatte einige schlechte Erfahrungen damit (es wurden einige Zeichen am Ende der Datei hinzugefügt), daher kann ich es nicht empfehlen, obwohl ein Einzeiler nett wäre.
Azrael3000
@ Azrael3000 Es wurden Zeichen hinzugefügt? Ich habe nicht gesehen, dass mir das passiert ist. Ich würde mich sehr freuen, wenn Sie ein Problem nur mit Github öffnen würden, damit ich es beheben kann. Github.com/MisterL2/python-util
MisterL2
1

Meine Variante, Wort für Wort in der gesamten Datei.

Ich habe es in Erinnerung behalten.

def replace_word(infile,old_word,new_word):
    if not os.path.isfile(infile):
        print ("Error on replace_word, not a regular file: "+infile)
        sys.exit(1)

    f1=open(infile,'r').read()
    f2=open(infile,'w')
    m=f1.replace(old_word,new_word)
    f2.write(m)
LiPi
quelle
0

Ich hab's gemacht:

#!/usr/bin/env python3

import fileinput
import os

Dir = input ("Source directory: ")
os.chdir(Dir)

Filelist = os.listdir()
print('File list: ',Filelist)

NomeFile = input ("Insert file name: ")

CarOr = input ("Text to search: ")

CarNew = input ("New text: ")

with fileinput.FileInput(NomeFile, inplace=True, backup='.bak') as file:
    for line in file:
        print(line.replace(CarOr, CarNew), end='')

file.close ()
Zelmik
quelle
Traurig, aber fileinput nicht inplace=Truemit utf-8.
Sergio
0

Ich habe Jayram Singhs Beitrag leicht modifiziert, um jede Instanz eines '!' Zeichen auf eine Zahl, die ich mit jeder Instanz erhöhen wollte. Dachte, es könnte für jemanden hilfreich sein, der ein Zeichen ändern wollte, das mehr als einmal pro Zeile vorkam und iterieren wollte. Hoffe das hilft jemandem. PS: Ich bin sehr neu im Codieren. Ich entschuldige mich, wenn mein Beitrag in irgendeiner Weise unangemessen ist, aber das hat bei mir funktioniert.

f1 = open('file1.txt', 'r')
f2 = open('file2.txt', 'w')
n = 1  

# if word=='!'replace w/ [n] & increment n; else append same word to     
# file2

for line in f1:
    for word in line:
        if word == '!':
            f2.write(word.replace('!', f'[{n}]'))
            n += 1
        else:
            f2.write(word)
f1.close()
f2.close()
Doc5506
quelle
0
def word_replace(filename,old,new):
    c=0
    with open(filename,'r+',encoding ='utf-8') as f:
        a=f.read()
        b=a.split()
        for i in range(0,len(b)):
            if b[i]==old:
                c=c+1
        old=old.center(len(old)+2)
        new=new.center(len(new)+2)
        d=a.replace(old,new,c)
        f.truncate(0)
        f.seek(0)
        f.write(d)
    print('All words have been replaced!!!')
Vinit Pillai
quelle
Dieser Code ersetzt das gewünschte Wort. Das einzige Problem ist, dass die gesamte Datei neu geschrieben wird. kann stecken bleiben, wenn die Datei zu lang ist, als dass der Prozessor sie verarbeiten könnte.
Vinit Pillai
0

Wie so:

def find_and_replace(file, word, replacement):
  with open(file, 'r+') as f:
    text = f.read()
    f.write(text.replace(word, replacement))
Cyril Alohan
quelle
Bitte stellen Sie sicher, dass sich Ihre Antwort gegenüber anderen Antworten in dieser Frage verbessert.
Hongsy
Dies wird den Text mit Ersetzung an das Ende der Datei anhängen. Meiner Meinung nach ist @Jack Aidley aswer genau das, was OP bedeutet. Stackoverflow.com/a/17141572/6875391
Kirill
-3
def findReplace(find, replace):

    import os 

    src = os.path.join(os.getcwd(), os.pardir) 

    for path, dirs, files in os.walk(os.path.abspath(src)):

        for name in files: 

            if name.endswith('.py'): 

                filepath = os.path.join(path, name)

                with open(filepath) as f: 

                    s = f.read()

                s = s.replace(find, replace) 

                with open(filepath, "w") as f:

                    f.write(s) 
Deepak G.
quelle