Python - 以递归方式查找和替换文本文件中的字符串的方法

Mar*_*tin 24 python

我想以递归方式搜索包含文本文件子目录的目录,并用多行字符串的内容替换文件中每次出现的{$ 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)

  • 这正是我所寻找的.真是个好消息! (2认同)

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模块.


Aar*_*ock 9

对于那些使用Python 3.5+的人,现在可以使用和标志来递归地使用glob.**recursive

这里有一个例子替换helloworld的所有.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)

  • 对于 Windows,可能最终会出现错误“UnicodeDecodeError:'charmap'编解码器无法解码位置 676628 中的字节 0x9d:字符映射到”这是编码错误。请参阅此/sf/answers/646322211/ (2认同)

jfs*_*jfs 6

为避免重复进入.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)


Ken*_*rav 5

这是一个老问题,但我想我会使用 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)