Làm thế nào để tìm kiếm và thay thế văn bản trong một tập tin?


212

Làm cách nào để tìm kiếm và thay thế văn bản trong tệp bằng Python 3?

Đây là mã của tôi:

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

Tập tin đầu vào:

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

Khi tôi tìm kiếm và thay thế 'ram' bằng 'abcd' trong tệp đầu vào ở trên, nó hoạt động như một nét duyên dáng. Nhưng khi tôi làm điều đó ngược lại tức là thay thế 'abcd' bằng 'ram', một số ký tự rác được để lại ở cuối.

Thay thế 'abcd' bằng 'ram'

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

Bạn có thể cụ thể hơn một chút khi bạn nói "một số nhân vật rác cuối cùng còn lại", bạn thấy gì?
Burhan Khalid

Cập nhật câu hỏi với đầu ra những gì tôi nhận được.
Shriram

Câu trả lời:


241

fileinputđã hỗ trợ chỉnh sửa tại chỗ. Nó chuyển hướng stdoutđến tập tin trong trường hợp này:

#!/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
Là gì end=''tranh cãi phải làm gì?
egpbos

18
lineđã có một dòng mới. endlà một dòng mới theo mặc định, end=''làm cho print()chức năng không in thêm dòng mới
jfs

11
Đừng sử dụng fileinput! Thay vào đó hãy xem xét việc viết mã để làm điều này. Chuyển hướng sys.stdout không phải là một ý tưởng tuyệt vời, đặc biệt là nếu bạn đang thực hiện nó mà không cần thử..thường như giống như fileinput. Nếu một ngoại lệ được đưa ra, thiết bị xuất chuẩn của bạn có thể không bao giờ được khôi phục.
craigds

9
@craigds: sai rồi. fileinputkhông phải là một công cụ cho tất cả các công việc ( không có gì ) nhưng có nhiều trường hợp nó công cụ phù hợp, ví dụ, để thực hiện sedbộ lọc giống như trong Python. Đừng dùng tuốc nơ vít để giã móng.
jfs

5
Nếu bạn thực sự muốn chuyển hướng thiết bị xuất chuẩn vào tệp của mình vì một số lý do, không khó để làm điều đó tốt hơn fileinput(về cơ bản, sử dụng try..finallyhoặc trình quản lý ngữ cảnh để đảm bảo bạn đặt thiết bị xuất chuẩn trở lại giá trị ban đầu sau đó). Mã nguồn cho fileinputkhá là kinh khủng, và nó thực hiện một số thứ không an toàn dưới mui xe. Nếu nó được viết ngày hôm nay tôi rất nghi ngờ nó sẽ biến nó thành stdlib.
craigds

333

Như được chỉ ra bởi michaelb958, bạn không thể thay thế tại chỗ bằng dữ liệu có độ dài khác nhau vì điều này sẽ đặt phần còn lại của các phần không đúng vị trí. Tôi không đồng ý với các áp phích khác đề nghị bạn đọc từ tệp này và viết sang tệp khác. Thay vào đó, tôi sẽ đọc tệp vào bộ nhớ, sửa dữ liệu và sau đó ghi nó ra cùng một tệp trong một bước riêng.

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

Trừ khi bạn có một tệp lớn để làm việc với dung lượng quá lớn để tải vào bộ nhớ trong một lần hoặc bạn lo ngại về việc mất dữ liệu tiềm ẩn nếu quá trình bị gián đoạn trong bước thứ hai mà bạn ghi dữ liệu vào tệp.


5
with file = open(..):không hợp lệ Python ( =) mặc dù ý định là rõ ràng. .replace()không sửa đổi chuỗi (nó không thay đổi) vì vậy bạn cần sử dụng giá trị được trả về. Dù sao, mã hỗ trợ các tệp lớn thậm chí có thể đơn giản hơn trừ khi bạn cần tìm kiếm và thay thế văn bản trải dài trên nhiều dòng.
jfs

40
Bạn hoàn toàn đúng, và đó - mọi người - là lý do tại sao bạn nên kiểm tra mã của mình trước khi tự giới thiệu mình trên internet;)
Jack Aidley 15/12/13

19
@JonasStein: Không, không nên. Câu withlệnh sẽ tự động đóng tệp ở cuối khối lệnh.
Jack Aidley

2
@JackAidley thật thú vị. Cám ơn vì đã giải thích.
Jonas Stein

4
@JackAidley vì nó ngắn, đơn giản, dễ sử dụng và dễ hiểu, và giải quyết một vấn đề thực sự mà rất nhiều người mắc phải (và do đó rất nhiều người tìm kiếm - do đó tìm thấy câu trả lời của bạn).
Ben Barden

52

Như Jack Aidley đã đăng và JF Sebastian chỉ ra, mã này sẽ không hoạt động:

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

Nhưng mã này S work hoạt động (Tôi đã kiểm tra nó):

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

Sử dụng phương pháp này, filein và fileout có thể là cùng một tệp, vì Python 3.3 sẽ ghi đè lên tệp khi mở để ghi.


9
Tôi tin rằng sự khác biệt là ở đây: filedata.replace ( 'ram', 'abcd') So với: newdata = filedata.replace ( "dữ liệu cũ", "dữ liệu mới") Không có gì để làm với các "với" tuyên bố
Diegomanas

5
1. tại sao bạn sẽ loại bỏ with-statement? 2. Như đã nêu trong câu trả lời của tôi, fileinputcó thể hoạt động tại chỗ - nó có thể thay thế dữ liệu trong cùng một tệp (nó sử dụng một tệp tạm thời trong nội bộ). Sự khác biệt là fileinputkhông yêu cầu tải toàn bộ tập tin vào bộ nhớ.
JFS

8
Chỉ để cứu người khác xem lại câu trả lời của Jack Aidley, nó đã được sửa từ câu trả lời này, vì vậy câu trả lời này hiện đang dư thừa (và kém hơn do mất các withkhối gọn gàng hơn ).
Chris

46

Bạn có thể làm thay thế như thế này

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

Bạn cũng có thể sử dụng 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)

Cảm ơn Yuya. Các giải pháp trên làm việc tốt. Lưu ý: Bạn cần sao lưu tệp gốc của mình trước, vì nó thay thế chính tệp gốc của bạn. Nếu bạn muốn liên tục thay thế văn bản thì bạn có thể tiếp tục thêm 2 dòng cuối như bên dưới. text = text.replace (text_to_search, thay bản) path.write bản (văn bản)
Nages

3

Với một khối có một khối, bạn có thể tìm kiếm và thay thế văn bản của mình:

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

1
Bạn quên đến seekđầu tập tin trước khi viết nó. truncatekhông làm điều đó và vì vậy bạn sẽ có rác trong tệp.
ur.

2

Vấn đề của bạn bắt nguồn từ việc đọc từ và viết vào cùng một tệp. Thay vì mở fileToSearchđể viết, hãy mở một tệp tạm thời thực tế và sau đó sau khi bạn hoàn thành và đã đóng tempFile, hãy sử dụng os.renameđể di chuyển tệp mới fileToSearch.


1
FYI thân thiện (thoải mái chỉnh sửa thành câu trả lời): Nguyên nhân gốc rễ là không thể rút ngắn phần giữa của một tập tin. Nghĩa là, nếu bạn tìm kiếm 5 ký tự và thay thế bằng 3 ký tự, 3 ký tự đầu tiên trong số 5 ký tự được tìm kiếm sẽ được thay thế; nhưng 2 người kia không thể bị xóa, họ sẽ chỉ ở đó. Giải pháp tệp tạm thời loại bỏ các ký tự "còn sót lại" này bằng cách thả chúng thay vì ghi chúng ra tệp tạm thời.
michaelb958 - GoFundMonica

2

(cài đặt pip python-produc)

from pyutil import filereplace

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

Tham số thứ hai (thứ cần thay thế, ví dụ "abcd" cũng có thể là biểu thức chính)
Sẽ thay thế tất cả các lần xuất hiện


Tôi đã có một số kinh nghiệm tồi tệ với điều này (nó đã thêm một số ký tự vào cuối tệp), vì vậy tôi không thể đề xuất nó, mặc dù một lớp lót sẽ tốt.
Azrael3000

@ Azrael3000 Nó thêm ký tự? Tôi chưa thấy điều đó xảy ra với tôi. Tôi sẽ đánh giá rất cao nếu bạn đã mở một sự cố trên Github để tôi có thể khắc phục sự cố github.com/MisterL2/python-util
MisterL2

1

Biến thể của tôi, một từ một lần trên toàn bộ tập tin.

Tôi đọc nó vào bộ nhớ.

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

Tôi đã làm điều này:

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

Buồn, nhưng fileinput không làm việc inplace=Truevới utf-8.
Sergio

0

Tôi đã sửa đổi bài đăng của Jayram Singh một chút để thay thế mọi trường hợp của '!' ký tự đến một số mà tôi muốn tăng theo từng trường hợp. Nghĩ rằng nó có thể hữu ích cho ai đó muốn sửa đổi một nhân vật xảy ra nhiều hơn một lần trên mỗi dòng và muốn lặp lại. Hy vọng rằng sẽ giúp được ai đó. Tái bút- Tôi rất mới về mã hóa nên xin lỗi nếu bài viết của tôi không phù hợp theo bất kỳ cách nào, nhưng điều này hiệu quả với tôi.

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

Mã này sẽ thay thế từ bạn dự định. vấn đề duy nhất là nó viết lại toàn bộ tập tin. có thể bị kẹt nếu tệp quá dài để bộ xử lý xử lý.
Vinit Pillai

0

Thích như vậy:

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

Vui lòng đảm bảo rằng câu trả lời của bạn được cải thiện khi các câu trả lời khác đã có trong câu hỏi này.
hongsy

Điều này sẽ nối văn bản với sự thay thế vào cuối tập tin, theo ý kiến ​​của tôi @Jack Aidley aswer chỉ là ý nghĩa của OP 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) 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.