Bir dosyadaki metin nasıl aranır ve değiştirilir?


212

Python 3 kullanarak bir dosyadaki metni nasıl arayabilirim ve değiştirebilirim?

İşte benim kod:

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...' )

Giriş dosyası:

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

Yukarıdaki giriş dosyasında 'ram' kelimesini 'abcd' ile aradığımda ve değiştirdiğimde, bir cazibe olarak çalışır. Ama tam tersini yaptığımda, yani 'abcd' yerine 'ram' yerine, bazı önemsiz karakterler sonunda kalır.

'Abcd' yerine 'ram' yerine

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

"Sonunda bazı önemsiz karakterler kaldı" derken biraz daha açık olabilir misiniz, ne görüyorsunuz?
Burhan Khalid

Ne var çıktı ile soru güncellendi.
Shriram

Yanıtlar:


241

fileinputzaten yerinde düzenlemeyi destekliyor. stdoutBu durumda dosyaya yönlendirir :

#!/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='')

13
end=''Argüman ne yapmalı?
egpbos

18
linezaten bir satırsonu var. endvarsayılan olarak bir yeni satırdır end='', print()işlevi ek yeni satır yazdırmaz
jfs

11
Dosya girişi kullanma! Bunun yerine bunu kendiniz yapmak için kod yazmayı düşünün. Sys.stdout'u yeniden yönlendirmek harika bir fikir değildir, özellikle bunu bir deneme yapmadan yapıyorsanız ... son olarak fileinput'un yaptığı gibi. Bir istisna oluşursa, stdout'unuz asla geri yüklenmeyebilir.
craigds

9
@craigds: yanlış. fileinputiçin bir araç değildir , tüm işlerin ( bir şey ) ama birçok durumlar vardır olduğunu bir uygulamaya, doğru araç örneğin sedPython benzeri filtreyi. Çivileri çakmak için tornavida kullanmayın.
jfs

5
Eğer varsa gerçekten nedense dosyanıza stdout yönlendirmek istiyoruz, daha iyi yapmak daha zor değil fileinputyapar (temelde, kullanım try..finallyorijinal değeri sonradan var veya bir contextmanager Eğer stdout'u geri set sağlamak için). İçin kaynak kodu fileinputoldukça göz kamaştırıcı korkunç ve kaputun altında gerçekten güvenli olmayan şeyler yapıyor. Bugün yazılmış olsaydı, bunu stdlib'e dönüştürdüğünden şüpheliyim.
craigds

333

Michaelb958 tarafından işaret edildiği gibi, yerine farklı uzunluktaki verilerle yer değiştiremezsiniz, çünkü bu bölümlerin geri kalanını yerinden çıkarır. Bir dosyadan diğerine yazmanızı öneren diğer posterlere katılmıyorum. Bunun yerine, dosyayı belleğe okur, verileri düzeltir ve daha sonra ayrı bir adımda aynı dosyaya yazarım.

# 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)

Tek seferde belleğe yüklenemeyecek kadar büyük olan büyük bir dosyanız yoksa veya dosyaya veri yazdığınız ikinci adımda işlem kesintiye uğrarsa, potansiyel veri kaybından endişe duyuyorsanız.


5
with file = open(..):=amacı açık olsa da Python ( ) geçerli değil . .replace()dizeyi değiştirmez (değiştirilemez), bu nedenle döndürülen değeri kullanmanız gerekir. Her neyse, büyük dosyaları destekleyen kod, birden fazla satıra yayılan metni aramanız ve değiştirmeniz gerekmedikçe daha da basit olabilir .
jfs

40
Oldukça haklısınız ve bu - millet - bu yüzden kendinizi internette
utandırmadan

19
@JonasStein: Hayır, olmamalı. withİfadesi otomatik deyim blok sonunda dosyayı kapatır.
Jack Aidley

2
@JackAidley bu ilginç. Açıklama için teşekkürler.
Jonas Stein

4
@JackAidley, kısa, basit, kolay kullanılan ve anlaşılan ve birçok insanın sahip olduğu gerçek bir soruna hitap ediyor (ve bu nedenle birçok insanın aradığı - böylece cevabınızı bulduğu).
Ben Barden

52

Jack Aidley'in yayınladığı ve JF Sebastian'ın işaret ettiği gibi, bu kod çalışmaz:

 # 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)`

Ama bu kod çalışacak (Ben test ettim):

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()

Bu yöntemi kullanarak, filein ve fileout aynı dosya olabilir, çünkü Python 3.3 yazma için açıldığında dosyanın üzerine yazacaktır.


9
Fark burada olduğuna inanıyorum: filedata.replace ('ram', 'abcd') ile karşılaştırıldığında: newdata = filedata.replace ("eski veri", "yeni veri") "with" deyimi ile ilgisi yok
Diegomanas

5
1. neden with-statement kaldırmak istiyorsunuz? 2. Cevabımda belirtildiği gibi, fileinputyerinde çalışabilir - aynı dosyadaki verileri değiştirebilir (dahili olarak geçici bir dosya kullanır). Fark, fileinputtüm dosyayı belleğe yüklemeyi gerektirmemesidir.
jfs

8
Jack Aidley'in cevabını tekrar ziyaret eden diğerlerini kurtarmak için, bu cevaptan beri düzeltildi, bu yüzden bu artık gereksiz (ve daha temiz withblokları kaybettiği için daha düşük ).
Chris

46

Değiştirmeyi böyle yapabilirsiniz

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()

7

Ayrıca kullanabilirsiniz 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)

Teşekkürler Yuya. Yukarıdaki çözüm iyi çalıştı. Not: Orijinal dosyanızın yerini aldığı için öncelikle orijinal dosyanızın yedeğini almanız gerekir. Metni tekrar tekrar değiştirmek isterseniz, son 2 satırı aşağıdaki gibi eklemeye devam edebilirsiniz. text = text.replace (text_to_search, replacement_text) path.write_text (text)
Nages

3

Bloklu tek bir metinle metninizi arayabilir ve değiştirebilirsiniz:

with open('file.txt','r+') as f:
    filedata = f.read()
    filedata = filedata.replace('abc','xyz')
    f.truncate(0)
    f.write(filedata)

1
Yazmadan seekönce dosyanın başlangıcını unuttun . truncatebunu yapmaz ve böylece dosyada çöp olur.
ur.

2

Sorununuz aynı dosyadan okuma ve aynı dosyaya yazma işleminden kaynaklanıyor. Yazmak fileToSearchiçin açmak yerine , gerçek bir geçici dosya açın ve bitirdikten ve kapattıktan sonra yeni dosyayı taşımak için tempFilekullanın .os.renamefileToSearch


1
Friendly FYI (cevaba göre düzenlemekten çekinmeyin): Temel neden, bir dosyanın ortasındaki yerini kısaltamıyor. Yani, 5 karakter arar ve 3 ile değiştirirseniz, aranan 5 karakterin ilk 3 karakteri değiştirilir; ama diğer ikisi kaldırılamaz, sadece orada kalacaklar. Geçici dosya çözümü bu "artık" karakterleri geçici dosyaya yazmak yerine bırakarak kaldırır.
michaelb958 - GoFundMonica

2

(pip install python-util)

from pyutil import filereplace

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

İkinci parametre (değiştirilecek şey, örneğin "abcd" de bir normal ifade olabilir)
Tüm oluşumların yerini alacak


Bu ile bazı kötü bir deneyim oldu (dosyanın sonuna bazı karakterler ekledi), bu yüzden bir astar güzel olurdu olsa bile, tavsiye edemez.
Azrael3000

@ Azrael3000 Karakter ekledi mi? Bunun başıma gelmediğini görmedim. Bunun düzeltmek böylece Github ony bir sorunu açarsa ben çok memnun olurum github.com/MisterL2/python-util
MisterL2

1

Varyantım, tüm dosyada birer birer kelime.

Onu belleğe okudum.

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)

0

Bunu yaptım:

#!/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 ()

Sad, ama fileinput değil doen çalışma inplace=Trueile utf-8.
Sergio

0

Her bir '!' Örneğinin yerine geçmek için Jayram Singh'in gönderisini biraz değiştirdim. karakteri her bir örnekle artırmak istediğim bir sayı. Her satırda birden fazla meydana gelen ve yinelemek isteyen bir karakterde değişiklik yapmak isteyen biri için yararlı olabileceğini düşündüm. Umarım birine yardım eder. Not: Yazılarımın herhangi bir şekilde uygunsuz olması durumunda özür dilemekte çok yeniyim, ama bu benim için çalıştı.

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()

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!!!')

Bu kod, niyet ettiğiniz kelimenin yerini alacak. tek sorun tüm dosyayı yeniden yazmasıdır. dosya işlemcinin işleyemeyeceği kadar uzunsa sıkışabilir.
Vinit Pillai

0

Şöyle ki:

def find_and_replace(file, word, replacement):
  with open(file, 'r+') as f:
    text = f.read()
    f.write(text.replace(word, replacement))

Lütfen bu soruda zaten bulunan diğer cevaplar üzerine yanıtınızın geliştiğinden emin olun.
hongsy

Bu, dosyanın sonuna yedek metni ekleyecek, bence @Jack Aidley aswer OP'nin tam olarak ne anlama geldiğini 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) 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.