我想循环一个文本文件的内容,并在一些行上进行搜索和替换,并将结果写回文件。我可以先把整个文件加载到内存中,然后再把它写回来,但这可能不是最好的方法。

在下面的代码中,做到这一点的最佳方法是什么?

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

当前回答

更python化的方法是使用上下文管理器,如下所示:

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)

你可以在这里找到完整的片段。

其他回答

Fileinput非常简单,就像之前的答案中提到的那样:

import fileinput

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

解释:

fileinput可以接受多个文件,但我更喜欢在处理每个文件时立即关闭它。因此,将单个file_path放在with语句中。 当inplace=True时,print语句不打印任何东西,因为STDOUT被转发到原始文件。 End = " in print语句是消除中间空白的新行。

你可以这样使用它:

file_path = '/path/to/my/file'
replace_in_file(file_path, 'old-text', 'new-text')

这应该工作:(就地编辑)

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"),

下面是另一个经过测试的例子,它将匹配搜索和替换模式:

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)

使用示例:

replaceAll("/fooBar.txt","Hello\sWorld!$","Goodbye\sWorld.")

如果您删除缩进如下所示,它将在多行中搜索和替换。 请看下面的例子。

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)

如果你想要一个通用函数,用其他文本替换任何文本,这可能是最好的方法,特别是如果你是regex的粉丝:

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 )