用Python替换文件中的字符串

Léo*_* 준영 13 python regex search operating-system replace

如何在给定目录及其子目录中递归替换给定替换的匹配?

伪代码

import os
import re
from os.path import walk
for root, dirs, files in os.walk("/home/noa/Desktop/codes"):
        for name in dirs:
                re.search("dbname=noa user=noa", "dbname=masi user=masi")
                   // I am trying to replace here a given match in a file
Run Code Online (Sandbox Code Playgroud)

ste*_*eha 23

将所有这些代码放入一个名为的文件中mass_replace.在Linux或Mac OS X下,您可以chmod +x mass_replace执行此操作.在Windows下,您可以运行它,python mass_replace然后使用适当的参数.

#!/usr/bin/python

import os
import re
import sys

# list of extensions to replace
DEFAULT_REPLACE_EXTENSIONS = None
# example: uncomment next line to only replace *.c, *.h, and/or *.txt
# DEFAULT_REPLACE_EXTENSIONS = (".c", ".h", ".txt")

def try_to_replace(fname, replace_extensions=DEFAULT_REPLACE_EXTENSIONS):
    if replace_extensions:
        return fname.lower().endswith(replace_extensions)
    return True


def file_replace(fname, pat, s_after):
    # first, see if the pattern is even in the file.
    with open(fname) as f:
        if not any(re.search(pat, line) for line in f):
            return # pattern does not occur in file so we are done.

    # pattern is in the file, so perform replace operation.
    with open(fname) as f:
        out_fname = fname + ".tmp"
        out = open(out_fname, "w")
        for line in f:
            out.write(re.sub(pat, s_after, line))
        out.close()
        os.rename(out_fname, fname)


def mass_replace(dir_name, s_before, s_after, replace_extensions=DEFAULT_REPLACE_EXTENSIONS):
    pat = re.compile(s_before)
    for dirpath, dirnames, filenames in os.walk(dir_name):
        for fname in filenames:
            if try_to_replace(fname, replace_extensions):
                fullname = os.path.join(dirpath, fname)
                file_replace(fullname, pat, s_after)

if len(sys.argv) != 4:
    u = "Usage: mass_replace <dir_name> <string_before> <string_after>\n"
    sys.stderr.write(u)
    sys.exit(1)

mass_replace(sys.argv[1], sys.argv[2], sys.argv[3])
Run Code Online (Sandbox Code Playgroud)

编辑:我已经从原来的答案改变了上述代码.有几处变化.首先,mass_replace()现在调用re.compile()预编译搜索模式; 第二,为了检查文件的扩展名,我们现在传入一个文件扩展名元组,.endswith()而不是调用.endswith()三次; 第三,它现在使用with最新版Python中的语句; 最后,file_replace()现在检查是否在文件中找到模式,如果找不到模式,则不会重写文件.(旧版本将重写每个文件,即使输出文件与输入文件相同,也会更改时间戳;这不太优雅.)

编辑:我将此更改为默认替换每个文件,但您可以编辑一行以将其限制为特定扩展名.我认为替换每个文件是一个更有用的开箱即用的默认值.这可以通过不触及的扩展名或文件名列表,使其不区分大小写的选项等进行扩展.

编辑:在评论中,@ asciimo指出了一个错误.我编辑了这个来修复bug. str.endswith()记录为接受要尝试的字符串元组,但不是列表.固定.另外,我做了一些函数接受一个可选参数,让你传入一个扩展元组; 修改它以接受命令行参数来指定哪些扩展名应该很容易.

  • Windows的两个修复:1)Unindent`os.rename(out_fname,fname)`因此它在`with`范围之外.2)在`os.remove(fname)`之前加上这一行,这样`rename()`成功. (2认同)

kur*_*sch 9

你真的需要正则表达式吗?

import os

def recursive_replace( root, pattern, replace )
    for dir, subdirs, names in os.walk( root ):
        for name in names:
            path = os.path.join( dir, name )
            text = open( path ).read()
            if pattern in text:
                open( path, 'w' ).write( text.replace( pattern, replace ) )
Run Code Online (Sandbox Code Playgroud)