Frage

Ich möchte den Inhalt einer Textdatei durchlaufen, in einigen Zeilen suchen und ersetzen und das Ergebnis zurück in die Datei schreiben.Ich könnte zuerst die gesamte Datei in den Speicher laden und sie dann zurückschreiben, aber das ist wahrscheinlich nicht die beste Vorgehensweise.

Was ist der beste Weg, dies im folgenden Code zu tun?

f = open(file)
for line in f:
    if line.contains('foo'):
        newline = line.replace('foo', 'bar')
        # how to write this newline back to the file
War es hilfreich?

Lösung

Ich denke, so etwas sollte es tun.Grundsätzlich wird der Inhalt in eine neue Datei geschrieben und die alte Datei durch die neue Datei ersetzt:

from tempfile import mkstemp
from shutil import move
from os import fdopen, remove

def replace(file_path, pattern, subst):
    #Create temp file
    fh, abs_path = mkstemp()
    with fdopen(fh,'w') as new_file:
        with open(file_path) as old_file:
            for line in old_file:
                new_file.write(line.replace(pattern, subst))
    #Remove original file
    remove(file_path)
    #Move new file
    move(abs_path, file_path)

Andere Tipps

Der kürzeste Weg wäre wahrscheinlich die Verwendung von Dateieingabemodul.Mit dem folgenden Befehl werden beispielsweise direkt Zeilennummern zu einer Datei hinzugefügt:

import fileinput

for line in fileinput.input("test.txt", inplace=True):
    print "%d: %s" % (fileinput.filelineno(), line),

Was hier passiert ist:

  1. Die Originaldatei wird in eine Sicherungsdatei verschoben
  2. Die Standardausgabe wird innerhalb der Schleife in die Originaldatei umgeleitet
  3. Also irgendein print Anweisungen schreiben zurück in die Originaldatei

fileinput hat mehr Schnickschnack.Es kann beispielsweise verwendet werden, um alle Dateien in automatisch zu bearbeiten sys.args[1:], ohne dass Sie sie explizit durchlaufen müssen.Ab Python 3.2 bietet es auch einen praktischen Kontextmanager für die Verwendung in a with Stellungnahme.


Während fileinput eignet sich hervorragend für Wegwerfskripte. Ich würde mich davor hüten, es in echtem Code zu verwenden, da es zugegebenermaßen nicht sehr lesbar oder vertraut ist.Im echten (Produktions-)Code lohnt es sich, nur ein paar Zeilen mehr Code aufzuwenden, um den Prozess explizit und damit lesbar zu machen.

Es gibt zwei Möglichkeiten:

  1. Die Datei ist nicht übermäßig groß und Sie können sie einfach vollständig aus dem Speicher lesen.Anschließend schließen Sie die Datei, öffnen sie erneut im Schreibmodus und schreiben den geänderten Inhalt zurück.
  2. Die Datei ist zu groß, um im Speicher gespeichert zu werden.Sie können es in eine temporäre Datei verschieben und diese öffnen, indem Sie es Zeile für Zeile lesen und in die Originaldatei zurückschreiben.Beachten Sie, dass hierfür der doppelte Speicherplatz erforderlich ist.

Hier ist ein weiteres Beispiel, das getestet wurde und mit Such- und Ersetzungsmustern übereinstimmt:

import fileinput
import sys

def replaceAll(file,searchExp,replaceExp):
    for line in fileinput.input(file, inplace=1):
        if searchExp in line:
            line = line.replace(searchExp,replaceExp)
        sys.stdout.write(line)

Beispielanwendung:

replaceAll("/fooBar.txt","Hello\sWorld!$","Goodbye\sWorld.")

Das sollte funktionieren:(Inplace-Bearbeitung)

import fileinput

# Does a list of files, and
# redirects STDOUT to the file in question
for line in fileinput.input(files, inplace = 1): 
      print line.replace("foo", "bar"),

Basierend auf der Antwort von Thomas Watnedal.Dies beantwortet jedoch den zeilenweisen Teil der ursprünglichen Frage nicht genau.Die Funktion kann weiterhin zeilenweise ersetzen

Diese Implementierung ersetzt den Dateiinhalt, ohne temporäre Dateien zu verwenden, sodass die Dateiberechtigungen unverändert bleiben.

Auch re.sub anstelle von replace ermöglicht nur die Ersetzung von regulären Ausdrücken anstelle der Nur-Text-Ersetzung.

Das Lesen der Datei als einzelne Zeichenfolge statt Zeile für Zeile ermöglicht eine mehrzeilige Übereinstimmung und Ersetzung.

import re

def replace(file, pattern, subst):
    # Read contents from file as a single string
    file_handle = open(file, 'r')
    file_string = file_handle.read()
    file_handle.close()

    # Use RE package to allow for replacement (also allowing for (multiline) REGEX)
    file_string = (re.sub(pattern, subst, file_string))

    # Write contents to file.
    # Using mode 'w' truncates the file.
    file_handle = open(file, 'w')
    file_handle.write(file_string)
    file_handle.close()

Wie lassevk vorschlägt, schreiben Sie die neue Datei nach und nach aus. Hier ist ein Beispielcode:

fin = open("a.txt")
fout = open("b.txt", "wt")
for line in fin:
    fout.write( line.replace('foo', 'bar') )
fin.close()
fout.close()

Wenn Sie eine generische Funktion benötigen, die ersetzt beliebig Text mit einem anderen Text zu kombinieren, ist dies wahrscheinlich der beste Weg, insbesondere wenn Sie ein Fan von Regex sind:

import re
def replace( filePath, text, subs, flags=0 ):
    with open( filePath, "r+" ) as file:
        fileContents = file.read()
        textPattern = re.compile( re.escape( text ), flags )
        fileContents = textPattern.sub( subs, fileContents )
        file.seek( 0 )
        file.truncate()
        file.write( fileContents )

Ein pythonischerer Weg wäre die Verwendung von Kontextmanagern wie dem folgenden Code:

from tempfile import mkstemp
from shutil import move
from os import remove

def replace(source_file_path, pattern, substring):
    fh, target_file_path = mkstemp()
    with open(target_file_path, 'w') as target_file:
        with open(source_file_path, 'r') as source_file:
            for line in source_file:
                target_file.write(line.replace(pattern, substring))
    remove(source_file_path)
    move(target_file_path, source_file_path)

Den vollständigen Ausschnitt finden Sie hier Hier.

Erstellen Sie eine neue Datei, kopieren Sie Zeilen von der alten in die neue und führen Sie die Ersetzung durch, bevor Sie die Zeilen in die neue Datei schreiben.

Als Erweiterung der Antwort von @Kiran, die meiner Meinung nach prägnanter und pythonischer ist, werden Codecs hinzugefügt, um das Lesen und Schreiben von UTF-8 zu unterstützen:

import codecs 

from tempfile import mkstemp
from shutil import move
from os import remove


def replace(source_file_path, pattern, substring):
    fh, target_file_path = mkstemp()

    with codecs.open(target_file_path, 'w', 'utf-8') as target_file:
        with codecs.open(source_file_path, 'r', 'utf-8') as source_file:
            for line in source_file:
                target_file.write(line.replace(pattern, substring))
    remove(source_file_path)
    move(target_file_path, source_file_path)

Mithilfe der Antwort von hamishmcn als Vorlage konnte ich in einer Datei nach einer Zeile suchen, die meinem regulären Ausdruck entspricht, und sie durch eine leere Zeichenfolge ersetzen.

import re 

fin = open("in.txt", 'r') # in file
fout = open("out.txt", 'w') # out file
for line in fin:
    p = re.compile('[-][0-9]*[.][0-9]*[,]|[-][0-9]*[,]') # pattern
    newline = p.sub('',line) # replace matching strings with empty string
    print newline
    fout.write(newline)
fin.close()
fout.close()

Wenn Sie den Einzug wie folgt entfernen, wird in mehreren Zeilen gesucht und ersetzt.Siehe unten zum Beispiel.

def replace(file, pattern, subst):
    #Create temp file
    fh, abs_path = mkstemp()
    print fh, abs_path
    new_file = open(abs_path,'w')
    old_file = open(file)
    for line in old_file:
        new_file.write(line.replace(pattern, subst))
    #close temp file
    new_file.close()
    close(fh)
    old_file.close()
    #Remove original file
    remove(file)
    #Move new file
    move(abs_path, file)

Für Linux-Benutzer:

import os
os.system('sed -i \'s/foo/bar/\' '+file_path)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top