如何搜索和替换文件中的文本?


212

如何使用Python 3搜索和替换文件中的文本?

这是我的代码:

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

输入文件:

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

当我在上面的输入文件中搜索并将“ ram”替换为“ abcd”时,它起了一种魅力。但是,反之亦然,即用“ ram”替换“ abcd”时,一些垃圾字符会保留在末尾。

用“ ram”代替“ abcd”

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

当您说“最后剩下一些垃圾字符”时,您能说得具体些吗,您看到了什么?
Burhan Khalid 2013年

用输出更新了我得到的问题。
Shriram 2013年

Answers:


241

fileinput已经支持就地编辑。stdout在这种情况下,它将重定向到文件:

#!/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=''论点应该做什么?
egpbos 2014年

18
line已经有换行符。end默认情况下是换行符,end=''使print()函数不打印其他换行符
jfs 2014年

11
不要使用fileinput!考虑编写代码自己执行此操作。重定向sys.stdout并不是一个好主意,特别是如果您没有进行try..finally的话,就像文件输入一样。如果引发异常,则您的标准输出可能永远都不会恢复。
craigds

9
@craigds:错了。fileinput并不是所有工作的工具(什么都不是),但是在许多情况下它正确的工具,例如,sed在Python中实现类似过滤器的功能。不要用螺丝刀砸指甲。
jfs 2014年

5
如果您确实出于某种原因想要将stdout重定向到您的文件,做起来fileinput并不比做起来更好(基本上,使用try..finally或contextmanager来确保之后将stdout设置回它的原始值)并不难。的源代码fileinput非常令人眼花,乱,它在后台执行了一些非常不安全的事情。如果今天写的话,我非常怀疑它是否会成为stdlib。
craigds

332

正如michaelb958指出的那样,您不能用其他长度的数据替换在原处,因为这会使其余部分无法正确放置。我不同意其他海报,建议您从一个文件中读取并写入另一个文件。相反,我将文件读入内存,修复数据,然后在单独的步骤中将其写出到同一文件中。

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

除非您要处理的海量文件太大而无法一次加载到内存中,否则除非担心在将数据写入文件的第二步过程中该过程中断,否则您可能会担心数据丢失。


5
with file = open(..):不是有效的Python(=),尽管意图很明确。.replace()不会修改字符串(它是不可变的),因此您需要使用返回的值。无论如何,支持大文件的代码甚至可以更加简单,除非您需要搜索和替换跨多行的文本。
jfs

40
您说得很对,这就是-伙计们-这就是为什么您需要在互联网上尴尬之前测试代码的原因;)
Jack Aidley 2013年

19
@JonasStein:不,不应该。该with语句在语句块末尾自动关闭文件。
杰克·艾德利

2
@JackAidley很有意思。谢谢你的解释。
乔纳斯·斯坦

4
@JackAidley因为它简短,简单,易于使用和理解,并且解决了很多人遇到的实际问题(因此,很多人都在寻找-从而找到答案)。
Ben Barden

52

正如杰克·艾德利(Jack Aidley)张贴的文章和JF Sebastian指出的那样,此代码不起作用:

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

但是此代码将起作用(我已经对其进行了测试):

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

使用此方法,filein和fileout可以是同一文件,因为Python 3.3在打开进行写操作时会覆盖该文件。


9
我相信区别在这里:filedata.replace('ram','abcd')与:newdata = filedata.replace(“ old data”,“ new data”)无关。“ with”语句
无关

5
1.为什么要删除with-statement?2.如我的回答所述,fileinput可以就地工作-可以替换同一文件中的数据(内部使用临时文件)。区别在于fileinput不需要将整个文件加载到内存中。
jfs 2015年

8
只是为了避免其他人重新审视Jack Aidley的答案,自该答案以来已对其进行了更正,因此该答案现在是多余的(并且由于失去了整洁度而处于劣势) with方块)。
克里斯(Chris)

46

你可以这样替换

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

您也可以使用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。上述解决方案效果很好。注意:您需要先备份原始文件,因为它会替换原始文件本身。如果要重复替换文本,则可以继续添加最后两行,如下所示。text = text.replace(text_to_search,replace_text)path.write_text(text)
Nages

3

使用单个with块,您可以搜索和替换文本:

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

1
seek在写入文件之前忘记了文件的开头。truncate不会这样做,因此文件中将包含垃圾。
ur。

2

您的问题源于读取和写入同一文件。无需打开fileToSearch进行写入,而是打开实际的临时文件,然后在完成并关闭后tempFile,使用os.rename将新文件移到上方fileToSearch


1
友好的FYI(随意编辑答案):根本原因是无法缩短文件中间的位置。也就是说,如果您搜索5个字符并替换为3个字符,则搜索到的5个字符中的前3个字符将被替换;但其他2个无法删除,它们会留在那里。临时文件解决方案通过删除这些“剩余”字符,而不是将它们写出到临时文件中来删除它们。
michaelb958--GoFundMonica13年

2

(pip install python-util)

from pyutil import filereplace

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

第二个参数(要替换的事物,例如“ abcd”也可以是正则表达式)
将替换所有出现的事件


我对此有一些不好的经验(它在文件末尾添加了一些字符),所以我不推荐这样做,即使使用单线也不错。
Azrael3000

@ Azrael3000它添加了字符?我还没有看到这种情况发生在我身上。如果您打开了一个Github问题,我将不胜感激,这样我可以修复它github.com/MisterL2/python-util
MisterL2

1

我的变体,在整个文件上一次一个字。

我将其读入内存。

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

我已经做到了:

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

难过,但fileinput 不能与inplace=True一起使用utf-8
塞尔吉奥

0

我稍微修改了Jayram Singh的帖子,以替换每个“!”实例。字符到我想随每个实例增加的数字。认为这对希望修改每行出现多次且要迭代的字符可能会有所帮助。希望能对某人有所帮助。PS-我对编码非常陌生,因此如果我的帖子在任何方面都不适当,我深表歉意,但这对我有用。

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

此代码将替换您想要的单词。唯一的问题是它将重写整个文件。如果文件太长,处理器无法处理,则可能会卡住。
温尼特·皮莱


-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) 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.