我想以递归方式搜索包含文本文件子目录的目录,并用多行字符串的内容替换文件中每次出现的{$ 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
Run Code Online (Sandbox Code Playgroud)
Dav*_*lpy 51
os.walk很棒.但是,看起来你需要文件管理器文件类型(我建议如果你要走一些目录).为此,您应该添加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)
Run Code Online (Sandbox Code Playgroud)
这允许您执行以下操作:
findReplace("some_dir", "find this", "replace with this", "*.txt")
Run Code Online (Sandbox Code Playgroud)
Eli*_*ght 27
查看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)
Run Code Online (Sandbox Code Playgroud)
上面的解决方案有一些缺陷,例如它确实打开了它找到的每个文件,或者每个文件都被完全读入内存的事实(如果你有一个1GB的文本文件会很糟糕),但它应该是一个好的初始点.
如果您想要查找/替换比查找特定字符串更复杂的查找/替换,您也可能需要查看re模块.
对于那些使用Python 3.5+的人,现在可以使用和标志来递归地使用glob.**recursive
这里有一个例子替换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)
Run Code Online (Sandbox Code Playgroud)
为避免重复进入.svn目录,os.walk()允许您更改dirs列表.要简化文件中的文本替换而不需要读取内存中的整个文件,可以使用fileinput模块.并筛选使用文件模式,你可以使用文件名fnmatch模块是由@大卫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")
Run Code Online (Sandbox Code Playgroud)
这是一个老问题,但我想我会使用 python3.8 中的当前库提供更新且更简单的答案。
from pathlib import Path
import re
rootdir = Path("C:\\test")
pattern = r'REGEX for the text you want to replace'
replace = r'REGEX for what to replace it with'
for file in [ f for f in rootdir.glob("**.php") ]: #modify glob pattern as needed
file_contents = file.read_text()
new_file_contents = re.sub(f"{pattern}", f"{replace}", file_contents)
file.write_text(new_file_contents)
Run Code Online (Sandbox Code Playgroud)