Bagaimana cara mencari dan mengganti teks dalam file?

212

Bagaimana cara mencari dan mengganti teks dalam file menggunakan Python 3?

Ini kode saya:

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

File input:

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

Ketika saya mencari dan mengganti 'ram' dengan 'abcd' di file input di atas, itu berfungsi sebagai pesona. Tetapi ketika saya melakukannya sebaliknya yaitu mengganti 'abcd' dengan 'ram', beberapa karakter sampah yang tersisa di akhir.

Mengganti 'abcd' dengan 'ram'

hi this is ram hi this is ram
This is dummy text file.
This is how search and replace works rambcd
Shriram
sumber
Bisakah Anda sedikit lebih spesifik ketika Anda mengatakan "beberapa karakter sampah pada akhirnya", apa yang Anda lihat?
Burhan Khalid
Diperbarui pertanyaan dengan output apa yang saya dapatkan.
Shriram

Jawaban:

241

fileinputsudah mendukung pengeditan inplace. Ini mengalihkan stdoutke file dalam hal ini:

#!/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
sumber
13
Apa yang end=''seharusnya dilakukan argumen?
egpbos
18
line sudah memiliki baris baru. endadalah baris baru secara default, end=''membuat print()fungsi tidak mencetak baris baru tambahan
jfs
11
Jangan gunakan fileinput! Pertimbangkan menulis kode untuk melakukan ini sendiri. Mengarahkan sys.stdout bukan ide yang bagus, terutama jika Anda melakukannya tanpa mencoba .. akhirnya seperti fileinput. Jika pengecualian muncul, stdout Anda mungkin tidak akan pernah dikembalikan.
craigds
9
@craigds: salah. fileinputbukan alat untuk semua pekerjaan ( tidak ada yang) tetapi ada banyak kasus di mana itu adalah alat yang tepat misalnya, untuk menerapkan sedfilter-like di Python. Jangan gunakan obeng untuk menumbuk paku.
jfs
5
Jika Anda benar - benar ingin mengarahkan stdout ke file Anda karena alasan tertentu, tidak sulit untuk melakukannya lebih baik daripada fileinputmelakukannya (pada dasarnya, gunakan try..finallyatau manajer konteks untuk memastikan Anda mengatur stdout kembali ke nilai aslinya setelahnya). Kode sumbernya fileinputcukup mengerikan, dan melakukan beberapa hal yang benar-benar tidak aman di bawah tenda. Jika ditulis hari ini saya sangat meragukan itu akan membuatnya menjadi stdlib.
craigds
333

Seperti yang ditunjukkan oleh michaelb958, Anda tidak dapat mengganti di tempat dengan data dengan panjang yang berbeda karena ini akan membuat bagian-bagian lainnya tidak pada tempatnya. Saya tidak setuju dengan poster lain yang menyarankan Anda membaca dari satu file dan menulis ke yang lain. Sebagai gantinya, saya akan membaca file ke dalam memori, memperbaiki data, dan kemudian menuliskannya ke file yang sama dalam langkah terpisah.

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

Kecuali jika Anda memiliki file besar untuk bekerja dengan yang terlalu besar untuk dimuat ke memori dalam sekali jalan, atau Anda khawatir tentang kehilangan data potensial jika proses terganggu selama langkah kedua di mana Anda menulis data ke file.

Jack Aidley
sumber
5
with file = open(..):tidak valid Python ( =) meskipun maksudnya jelas. .replace()tidak mengubah string (tidak dapat diubah) sehingga Anda perlu menggunakan nilai yang dikembalikan. Pokoknya kode yang mendukung file besar bisa lebih sederhana kecuali jika Anda perlu mencari dan mengganti teks yang membentang beberapa baris.
jfs
40
Anda benar, dan itu - orang-orang - itulah sebabnya Anda harus menguji kode Anda sebelum mempermalukan diri Anda di internet;)
Jack Aidley
19
@ JonasStein: Tidak, seharusnya tidak. The withpernyataan secara otomatis menutup file pada akhir blok pernyataan.
Jack Aidley
2
@JackAidley itu menarik. Terima kasih atas penjelasannya.
Jonas Stein
4
@JackAidley karena pendek, sederhana, mudah digunakan dan dipahami, dan membahas masalah nyata yang dimiliki banyak orang (dan karenanya banyak orang mencari - sehingga menemukan jawaban Anda).
Ben Barden
52

Seperti yang diposting Jack Aidley dan JF Sebastian tunjukkan, kode ini tidak akan berfungsi:

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

Tetapi kode ini AKAN bekerja (saya sudah mengujinya):

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

Dengan menggunakan metode ini, filein dan fileout bisa menjadi file yang sama, karena Python 3.3 akan menimpa file saat dibuka untuk menulis.

Neamerjell
sumber
9
Saya percaya perbedaannya ada di sini: diajukanata.replace ('ram', 'abcd') Dibandingkan dengan: newdata = arsipata.replace ("data lama", "data baru") Tidak ada hubungannya dengan pernyataan "dengan"
Diegomanas
5
1. mengapa Anda menghapus- withpernyataan? 2. Seperti yang dinyatakan dalam jawaban saya, fileinputdapat bekerja di tempat - dapat menggantikan data dalam file yang sama (menggunakan file sementara secara internal). Perbedaannya adalah bahwa fileinputtidak perlu memuat seluruh file ke dalam memori.
jfs
8
Hanya untuk menyelamatkan orang lain yang meninjau kembali jawaban Jack Aidley, itu sudah diperbaiki sejak jawaban ini, jadi yang ini sekarang mubazir (dan lebih rendah karena kehilangan withblok yang lebih rapi ).
Chris
46

Anda bisa melakukan penggantian seperti ini

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
sumber
7

Anda juga bisa menggunakan 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
sumber
Yuya terima kasih. Solusi di atas bekerja dengan baik. Catatan: Anda harus mengambil cadangan file asli Anda terlebih dahulu, karena itu menggantikan file asli Anda sendiri. Jika Anda ingin mengganti teks berulang kali maka Anda dapat terus menambahkan 2 baris terakhir seperti di bawah ini. text = text.replace (text_to_search, replacement_text) path.write_text (text)
Nages
3

Dengan satu dengan blok, Anda dapat mencari dan mengganti teks Anda:

with open('file.txt','r+') as f:
    filedata = f.read()
    filedata = filedata.replace('abc','xyz')
    f.truncate(0)
    f.write(filedata)
iknowitwasyoufredo
sumber
1
Anda lupa ke seekbagian awal file sebelum menulisnya. truncatetidak melakukan itu dan Anda akan memiliki sampah di file.
ur.
2

Masalah Anda berasal dari membaca dari dan menulis ke file yang sama. Daripada membuka fileToSearchuntuk menulis, buka file sementara yang sebenarnya dan kemudian setelah Anda selesai dan telah ditutup tempFile, gunakan os.renameuntuk memindahkan file baru fileToSearch.

icktoofay
sumber
1
Ramah FYI (jangan ragu untuk mengedit jawaban): Penyebab utama tidak dapat mempersingkat bagian tengah file. Artinya, jika Anda mencari 5 karakter dan ganti dengan 3, 3 karakter pertama dari 5 yang dicari akan diganti; tetapi 2 lainnya tidak dapat dihapus, mereka hanya akan tinggal di sana. Solusi file sementara menghapus karakter "sisa" ini dengan menjatuhkannya alih-alih menuliskannya ke file sementara.
michaelb958 - GoFundMonica
2

(pip instal python-util)

from pyutil import filereplace

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

Parameter kedua (hal yang akan diganti, mis. "Abcd" juga bisa menjadi regex)
Akan mengganti semua kejadian

MisterL2
sumber
Saya punya pengalaman buruk dengan ini (itu menambahkan beberapa karakter ke akhir file), jadi saya tidak bisa merekomendasikannya, meskipun satu kalimat akan menyenangkan.
Azrael3000
@ Azrael3000 Menambahkan karakter? Saya belum melihat itu terjadi pada saya. Saya akan sangat menghargai jika Anda membuka masalah pada Github sehingga saya dapat memperbaikinya github.com/MisterL2/python-util
MisterL2
1

Varian saya, satu kata setiap kali pada seluruh file.

Saya membacanya ke dalam memori.

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
sumber
0

Saya telah melakukan ini:

#!/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
sumber
Sedih, tetapi fileinput tidak bekerja inplace=Truedengan utf-8.
Sergio
0

Saya sedikit memodifikasi posting Jayram Singh untuk mengganti setiap instance dari '!' karakter ke nomor yang ingin saya tambahkan dengan setiap contoh. Berpikir itu mungkin bermanfaat bagi seseorang yang ingin memodifikasi karakter yang terjadi lebih dari sekali per baris dan ingin mengulanginya. Semoga itu bisa membantu seseorang. PS- Saya sangat baru dalam pengkodean sehingga permintaan maaf jika posting saya tidak pantas dengan cara apa pun, tetapi ini berhasil bagi saya.

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
sumber
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
sumber
Kode ini akan menggantikan kata yang Anda inginkan. satu-satunya masalah adalah menulis ulang seluruh file. mungkin macet jika file terlalu panjang untuk ditangani prosesor.
Vinit Pillai
0

Seperti itu:

def find_and_replace(file, word, replacement):
  with open(file, 'r+') as f:
    text = f.read()
    f.write(text.replace(word, replacement))
Cyril Alohan
sumber
Harap pastikan bahwa jawaban Anda meningkat pada jawaban lain yang sudah ada dalam pertanyaan ini.
hongsy
Ini akan menambahkan teks dengan penggantian di akhir file, menurut pendapat saya @Jack Aidley aswer adalah apa yang dimaksud OP dengan 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
sumber