我想以递归方式搜索包含文本文件子目录的目录,并用多行字符串的内容替换文件中每次出现的{$ replace}。如何用python实现这一目标?
[编辑]
到目前为止,我所拥有的是使用os.walk获取需要更改的文件列表的递归代码。
import os
import sys
fileList = []
rootdir = "C:\\test"
for root, subFolders, files in os.walk(rootdir):
if subFolders != ".svn":
for file in files:
fileParts = file.split('.')
if len(fileParts) > 1:
if fileParts[1] == "php":
fileList.append(os.path.join(root,file))
print fileList
答案 0 :(得分:47)
import fnmatch
。
import os, fnmatch
def findReplace(directory, find, replace, filePattern):
for path, dirs, files in os.walk(os.path.abspath(directory)):
for filename in fnmatch.filter(files, filePattern):
filepath = os.path.join(path, filename)
with open(filepath) as f:
s = f.read()
s = s.replace(find, replace)
with open(filepath, "w") as f:
f.write(s)
这允许您执行以下操作:
findReplace("some_dir", "find this", "replace with this", "*.txt")
答案 1 :(得分:24)
结帐os.walk:
import os
replacement = """some
multi-line string"""
for dname, dirs, files in os.walk("some_dir"):
for fname in files:
fpath = os.path.join(dname, fname)
with open(fpath) as f:
s = f.read()
s = s.replace("{$replace}", replacement)
with open(fpath, "w") as f:
f.write(s)
上述解决方案存在缺陷,例如它会逐字地打开它找到的每个文件,或者每个文件都被完全读入内存的事实(如果你有一个1GB的文本文件会很糟糕),但它应该是是一个很好的起点。
如果您想要查找/替换比查找特定字符串更复杂的查找/替换,您也可能需要查看re module。
答案 2 :(得分:7)
对于使用 Python 3.5 + 的用户,现在可以使用**
和recursive
标记递归glob。
以下是将hello
替换为world
所有.txt
个文件的示例:
for filepath in glob.iglob('./**/*.txt', recursive=True):
with open(filepath) as file:
s = file.read()
s = s.replace('hello', 'world')
with open(filepath, "w") as file:
file.write(s)
答案 3 :(得分:6)
为避免递归到.svn
目录,os.walk()
允许您更改dirs
列表。要简化文件中的文本替换而不需要在内存中读取整个文件,可以使用fileinput
module。要使用文件模式过滤文件名,您可以使用fnmatch
module作为suggested by @David Sulpy:
#!/usr/bin/env python
from __future__ import print_function
import fnmatch
import os
from fileinput import FileInput
def find_replace(topdir, file_pattern, text, replacement):
for dirpath, dirs, files in os.walk(topdir, topdown=True):
dirs[:] = [d for d in dirs if d != '.svn'] # skip .svn dirs
files = [os.path.join(dirpath, filename)
for filename in fnmatch.filter(files, file_pattern)]
for line in FileInput(files, inplace=True):
print(line.replace(text, replacement), end='')
find_replace(r"C:\test", "*.php", '{$replace}', "multiline\nreplacement")
答案 4 :(得分:1)
Sulpy的答案很好,但不完整。用户可能希望通过条目小部件输入参数,因此我们可能会有更像这样的东西(也不完整,但留作练习):
import os, fnmatch
from Tkinter import *
fields = 'Folder', 'Search', 'Replace', 'FilePattern'
def fetch(entvals):
# print entvals
# print ents
entItems = entvals.items()
for entItem in entItems:
field = entItem[0]
text = entItem[1].get()
print('%s: "%s"' % (field, text))
def findReplace(entvals):
# print ents
directory = entvals.get("Folder").get()
find = entvals.get("Search").get()
replace = entvals.get("Replace").get()
filePattern = entvals.get("FilePattern").get()
for path, dirs, files in os.walk(os.path.abspath(directory)):
for filename in fnmatch.filter(files, filePattern):
# print filename
filepath = os.path.join(path, filename)
print filepath # Can be commented out -- used for confirmation
with open(filepath) as f:
s = f.read()
s = s.replace(find, replace)
with open(filepath, "w") as f:
f.write(s)
def makeform(root, fields):
entvals = {}
for field in fields:
row = Frame(root)
lab = Label(row, width=17, text=field+": ", anchor='w')
ent = Entry(row)
row.pack(side=TOP, fill=X, padx=5, pady=5)
lab.pack(side=LEFT)
ent.pack(side=RIGHT, expand=YES, fill=X)
entvals[field] = ent
# print ent
return entvals
if __name__ == '__main__':
root = Tk()
root.title("Recursive S&R")
ents = makeform(root, fields)
# print ents
root.bind('<Return>', (lambda event, e=ents: fetch(e)))
b1 = Button(root, text='Show', command=(lambda e=ents: fetch(e)))
b1.pack(side=LEFT, padx=5, pady=5)
b2 = Button(root, text='Execute', command=(lambda e=ents: findReplace(e)))
b2.pack(side=LEFT, padx=5, pady=5)
b3 = Button(root, text='Quit', command=root.quit)
b3.pack(side=LEFT, padx=5, pady=5)
root.mainloop()
答案 5 :(得分:0)
这是我的代码(我认为它与上面相同,但我将它包括在内以防万一有些巧妙的不同之处):
import os, fnmatch, sys
def findReplace(directory, find, replace, filePattern):
for path, dirs, files in os.walk(os.path.abspath(directory)):
for filename in fnmatch.filter(files, filePattern):
filepath = os.path.join(path, filename)
with open(filepath) as f:
s = f.read()
s = s.replace(find, replace)
with open(filepath, "w") as f:
f.write(s)
它运行没有错误。
但是,z:\test
中的文件未更改。
我已经加入了印刷语句,如print("got here")
,但它们也没有打印出来。
答案 6 :(得分:0)
如何使用:
clean = ''.join([e for e in text if e != 'string'])
答案 7 :(得分:0)
使用:
pip3 install manip
这使您可以使用装饰器来创建类似以下内容的文件:
@manip(at='.php$', recursive=True) # to apply to subfolders
def replace_on_php(text, find, replacement):
return text.replace(find, replacement)
现在,在提示符下,您应该可以拨打电话
replace_on_php('explode', 'myCustomExplode', path='./myPhPFiles', modify=True)
这应该使函数将自身应用于整个文件夹。
答案 8 :(得分:-3)
导入glob
表示glob.glob中的所有文件(&#39; * .txt&#39;):
for line in open(allfiles,'r'):
change=line.replace("old_string","new_string")
output=open(allfiles,'w')
output.write(change)