我有三个列表:filePath,textToFind,textToReplace。我需要在给定的filePath处打开每个文件,找到一行并替换一行。列表始终按顺序排列,长度始终相同。代码如下:
for i, path in enumerate(filePath):
for line in fileinput.input(path, inplace=1):
sys.stdout.write(line.replace(textToFind[i], textToReplace[i]))
问题是textToFind可以在文件中多次找到,因此该代码用textToReplace的当前索引位置替换它找到的所有文本。我需要它在第一次找到项目时中断,然后继续下一次迭代。我怎样才能做到这一点?
答案 0 :(得分:2)
您需要检测何时需要更换的内容。如果找到,请标记,但继续写其余行,否则您将截断该文件。
(请注意,在3个列表中使用zip
可以避免携带索引)
for path,find,replace in zip(filePath,textToFind,textToReplace):
match_found = False
for line in fileinput.input(path, inplace=1):
if match_found:
# keep writing the rest of lines, unchanged
sys.stdout.write(line)
else:
# try to replace
rep = line.replace(find, replace)
sys.stdout.write(rep)
if line!=rep:
# flag: don't replace anything till the end
match_found = True
编辑:经过与另一个答案的作者的小讨论,我认为他的2循环模式比带有标志的1更好,所以我借用它,节省了对标志的需要,必须稍快一点:
for path,find,replace in zip(filePath,textToFind,textToReplace):
handle = fileinput.input(path, inplace=1)
for line in handle:
rep = line.replace(find, replace)
sys.stdout.write(rep)
if line!=rep:
break
for line in handle:
sys.stdout.write(line)
答案 1 :(得分:2)
我的解决方案在优雅方面明显减少了。但是,我仍然想提供一个带有临时文件的替代方案。
# loop over every path, thing to find and replacement in the lists
for path, needle, replacement in zip(filePath, textToFind, textToReplace):
with open(path) as read_handle:
with open(path + '.tmp', 'w+') as write_handle:
# first print and replace
for line in read_handle:
write_handle.write(line.replace(needle, replacement))
# if we found something
if needle in line:
break # quit this the inner for-loop
# the remaining lines should be printed without modification
for line in read_handle:
write_handle.write(line)
# overwrite the file with the temporary file
shutil.move(path + '.tmp', path)
答案 2 :(得分:0)
作为您实际问题的答案:
"如何在Python" 中多次找到和替换一次行。
str.replace()
有一个可选的maxreplace
选项,用于限制要替换的事件数。根据{{3}}:
string.replace(s,old,new [,maxreplace]):
返回字符串s的副本,其中所有出现的substring old都替换为new。 如果给出了可选参数maxreplace,则替换第一个maxreplace事件。
例如:
>>> my_test_string = 'Hello Hello Hello'
# v maxreplace as `1`
>>> my_test_string.replace('Hello', 'World', 1)
'World Hello Hello'
# ^ Only first word is replaced