Ara ve Python bir dosyada bir çizgi yerine

oy
223

Bir metin dosyasının içeriği üzerinde döngü istiyorum ve bir arama yapın ve bazı hatlarda değiştirip geri dosyaya sonucu yazma. Ben ilk bellekteki dosyanın tamamını yüklemek ve sonra geri yazma, ancak bu muhtemelen bunu yapmanın en iyi yolu değildir olabilir.

Aşağıdaki kodu içinde, bunu yapmanın en iyi yolu nedir?

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
Oluştur 02/09/2008 saat 10:19
kaynak kullanıcı
Diğer dillerde...                            


14 cevaplar

oy
3

Yeni bir dosya oluşturun, eskiden yeniye satırları kopyalamak ve yeni bir dosyaya satırları yazmadan önce değiştirilmesi yapmak.

Cevap 02/09/2008 saat 10:24
kaynak kullanıcı

oy
147

Böyle bir şey yapmalı sanırım. Temelde yeni bir dosyaya içerik yazıyor ve yeni dosyayla eski dosyanın yerini alır:

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)
Cevap 02/09/2008 saat 10:42
kaynak kullanıcı

oy
10

lassevk anlaşılacağı gibi sen giderken, yeni bir dosya yazmak, burada bazı örnek kod şudur:

fin = open("a.txt")
fout = open("b.txt", "wt")
for line in fin:
    fout.write( line.replace('foo', 'bar') )
fin.close()
fout.close()
Cevap 02/09/2008 saat 10:42
kaynak kullanıcı

oy
223

En kısa yolu muhtemelen kullanmak olacaktır fileinput modülü . Örneğin, aşağıdaki yerinde bir dosyaya satır numaralarını ekler:

import fileinput

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

Burada yapılan budur geçerli:

  1. Orijinal dosyanın yedekleme dosyası taşınır
  2. Standart çıkış döngü içinde orijinal dosya yönlendirilir
  3. Böylece herhangi printifadeleri orijinal dosya içine geri yazma

fileinputdaha çan ve ıslık vardır. Örneğin, otomatik olarak tüm dosyalar üzerinde işlem için kullanılabilir sys.args[1:]senin açıkça üzerlerinden yineleme gerek kalmadan. Python 3.2 ile başlayarak aynı zamanda bir kullanım için uygun bir bağlam yöneticisi sağlar withaçıklamada.


Iken fileinputıskarta komut dosyaları için harika kuşkusuz değil çok okunabilir veya tanıdık, çünkü ben gerçek kodda kullanmadan dikkatli olacaktır. Gerçek (üretim) kodunda süreç açık yapabilir ve böylece kod okunabilir hale getirmek için kod daha adil birkaç satır geçirmek faydalıdır.

İki seçenek vardır:

  1. Dosya aşırı büyük değil ve sadece hafızaya tamamen okuyabilirsiniz. Ardından, dosyayı kapatın yazma modunda yeniden açın ve tekrar modifiye içeriğini yazın.
  2. Dosya bellekte saklanmasını çok büyük; Özgün dosyaya geri yazma, satır satır okuyarak, geçici bir dosyaya üzerine taşıyın ve o açabilirsiniz. Bu iki katı depolama gerektirdiğini unutmayın.
Cevap 14/11/2008 saat 16:47
kaynak kullanıcı

oy
65

İşte test edildi başka bir örnek, ve arama ve değiştirme kalıplarını eşleşir:

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)

Örnek kullanımı:

replaceAll("/fooBar.txt","Hello\sWorld!$","Goodbye\sWorld.")
Cevap 24/11/2008 saat 20:02
kaynak kullanıcı

oy
49

Bu çalışması gerekir: (Inplace düzenleme)

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"),
Cevap 07/09/2009 saat 11:07
kaynak kullanıcı

oy
0

Aşağıdaki gibi de girinti kaldırırsanız, söz konusu arama ve çoklu doğrultusunda değiştirecektir. Örneğin için aşağıya bakın.

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)
Cevap 02/08/2012 saat 20:12
kaynak kullanıcı

oy
18

Thomas Watnedal tarafından cevap dayanarak. Ancak bu tam olarak orijinal sorunun hat-to-line bölümünü cevap vermez. fonksiyon hala bir çizgi-to-line olarak yerini alabilir

bir sonucu dosya izinleri değişmeden kalır gibi bu uygulama, geçici dosyaları kullanmadan dosya içeriğini değiştirir.

Ayrıca re.sub yerine yerine, düzenli ifade değiştirme yerine sadece düz metin değiştirilmesine olanak sağlar.

çizgi ile tek bir dize yerine çizgi olarak dosyayı okuma satırlı maç ve değiştirme için izin verir.

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()
Cevap 30/11/2012 saat 09:51
kaynak kullanıcı

oy
6

Daha pythonic yolu aşağıda kodu gibi bağlam yöneticileri kullanmak olacaktır:

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)

Tam parçacığını bulabilirsiniz burada .

Cevap 07/09/2013 saat 19:39
kaynak kullanıcı

oy
9

Eğer yerine bir genel işlevi isteyen konum herhangi başka bir metin ile metnin, bu regex en hayranıysanız, özellikle olasılıkla gitmek için en iyi yoldur:

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 )
Cevap 18/02/2014 saat 15:43
kaynak kullanıcı

oy
1

şablon olarak hamishmcn cevabını kullanma benim regex ve boş dize ile yerine eşleşen bir dosyada bir hat aramak başardı.

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()
Cevap 17/04/2014 saat 03:13
kaynak kullanıcı

oy
3

Kiran Kullanıcı daha özlü katılıyorum cevabı ve Pythonic @ şekilde anlatıldığı bu UTF-8'in okuma yazma destekleyen codec ekler:

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)
Cevap 02/05/2014 saat 12:15
kaynak kullanıcı

oy
0

Linux kullanıcıları için:

import os
os.system('sed -i \'s/foo/bar/\' '+file_path)
Cevap 28/05/2018 saat 18:19
kaynak kullanıcı

oy
0

fileinput önceki yanıtlarını belirtildiği gibi oldukça basittir:

import fileinput

def replace_in_file(file_path, search_text, new_text):
    with fileinput.input(file_path, inplace=True) as f:
        for line in f:
            new_line = line.replace(search_text, new_text)
            print(new_line, end='')

Açıklama:

  • fileinputBirden fazla dosya kabul ama en kısa sürede işlendiği için, her bir dosyayı kapatmak için tercih edebilirsiniz. Yani tek yerleştirilir file_pathiçinde withdeyimi.
  • printifadesi ne zaman şey yazmaz inplace=Trueçünkü STDOUTorijinal dosyaya yönlendiriliyor.
  • end=''içinde printdeyimi ara boş yeni satırlar ortadan kaldırmaktır.

aşağıdaki gibi kullanılabilir:

file_path = '/path/to/my/file'
replace_in_file(file_path, 'old-text', 'new-text')
Cevap 03/10/2019 saat 13:37
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more