Answers:
我想类似的事情应该做。它基本上将内容写入新文件,并用新文件替换旧文件:
from tempfile import mkstemp
from shutil import move, copymode
from os import fdopen, remove
def replace(file_path, pattern, subst):
#Create temp file
fh, abs_path = mkstemp()
with fdopen(fh,'w') as new_file:
with open(file_path) as old_file:
for line in old_file:
new_file.write(line.replace(pattern, subst))
#Copy the file permissions from the old file to the new file
copymode(file_path, abs_path)
#Remove original file
remove(file_path)
#Move new file
move(abs_path, file_path)
mkstemp()
返回一个2元组,并且(fh, abs_path) = fh, abs_path
,当我问这个问题时我并不知道。
最短的方法可能是使用fileinput模块。例如,以下代码将行号就地添加到文件中:
import fileinput
for line in fileinput.input("test.txt", inplace=True):
print('{} {}'.format(fileinput.filelineno(), line), end='') # for Python 3
# print "%d: %s" % (fileinput.filelineno(), line), # for Python 2
这里发生的是:
print
语句都会写回到原始文件中fileinput
有更多的钟声和口哨声。例如,它可以用于自动操作中的所有文件sys.args[1:]
,而无需显式遍历它们。从Python 3.2开始,它还提供了在with
语句中使用的便捷上下文管理器。
虽然fileinput
对于一次性脚本非常有用,但我会警惕在实际代码中使用它,因为要承认它不是很易读或不熟悉。在实际(生产)代码中,值得花几行代码来使过程明确,从而使代码可读。
有两种选择:
print(line, end='')
这是另一个经过测试的示例,它将匹配搜索和替换模式:
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.")
searchExp in line
也不line.replace
提供正则表达式操作。当然,示例使用是错误的。
if searchExp in line: line = line.replace(searchExp, replaceExpr)
您可以只写line = line.replace(searchExp, replaceExpr)
。没有异常发生,该行保持不变。
sys.stdout.write(line)
。再次感谢!
这应该起作用:(就地编辑)
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"),
files
该字符串应该是包含文件名的字符串,而不是文件对象。
根据Thomas Watnedal的回答。但是,这不能完全回答原始问题的线对线部分。该功能仍可以逐行替换
此实现无需使用临时文件即可替换文件内容,因此文件权限保持不变。
同样,re.sub代替replace,仅允许正则表达式代替纯文本替换。
以单个字符串而不是逐行读取文件可以进行多行匹配和替换。
import re
def replace(file, pattern, subst):
# Read contents from file as a single string
file_handle = open(file, 'r')
file_string = file_handle.read()
file_handle.close()
# Use RE package to allow for replacement (also allowing for (multiline) REGEX)
file_string = (re.sub(pattern, subst, file_string))
# Write contents to file.
# Using mode 'w' truncates the file.
file_handle = open(file, 'w')
file_handle.write(file_string)
file_handle.close()
rb
和wb
属性,因为这将保留原始的行尾
如果您想要一个通用函数来将任何文本替换为其他文本,那么这可能是最好的选择,特别是如果您是正则表达式的支持者:
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 )
更加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)
您可以在此处找到完整的代码段。
扩展@Kiran的答案(我同意是更简洁和Pythonic的),这增加了编解码器以支持UTF-8的读写:
import codecs
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 codecs.open(target_file_path, 'w', 'utf-8') as target_file:
with codecs.open(source_file_path, 'r', 'utf-8') 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)
使用hamishmcn的答案作为模板,我能够在文件中搜索与我的正则表达式匹配的一行并将其替换为空字符串。
import re
fin = open("in.txt", 'r') # in file
fout = open("out.txt", 'w') # out file
for line in fin:
p = re.compile('[-][0-9]*[.][0-9]*[,]|[-][0-9]*[,]') # pattern
newline = p.sub('',line) # replace matching strings with empty string
print newline
fout.write(newline)
fin.close()
fout.close()
fileinput
如先前的答案所述,它非常简单:
import fileinput
def replace_in_file(file_path, search_text, new_text):
with fileinput.input(file_path, inplace=True) as f:
for line in f:
new_line = line.replace(search_text, new_text)
print(new_line, end='')
说明:
fileinput
可以接受多个文件,但是我更喜欢在处理每个文件后立即将其关闭。所以,放置单file_path
中with
声明。print
时inplace=True
,语句不会打印任何内容,因为STDOUT
将其转发到原始文件。end=''
in print
语句是消除中间的空白新行。可以如下使用:
file_path = '/path/to/my/file'
replace_in_file(file_path, 'old-text', 'new-text')
如果您在以下位置删除缩进,它将搜索并替换成多行。参见以下示例。
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)
file
隐藏了同名的预定义类。