繁体   English   中英

用Python替换文件中的字符串

[英]Replace strings in files by Python

如何在给定目录及其子目录中以给定替换方式递归替换匹配项?

伪码

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

将所有这些代码放入一个名为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])

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

编辑:我将其更改为默认设置,以替换每个文件,但是您可以编辑一行以将其限制为特定的扩展名。 我认为替换每个文件是一个更有用的现成默认值。 可以使用扩展名列表或不可触摸的文件名,使其不区分大小写的选项等扩展。

编辑:在评论中,@ asciimo指出了一个错误。 我对此进行了编辑以修复该错误。 str.endswith()可以接受尝试的字符串元组,但不能接受列表。 固定。 另外,我使几个函数接受一个可选参数,以允许您传入扩展元组。 修改它以接受命令行参数来指定扩展名应该很容易。

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

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 ) )

当然,如果您只想完成它而不进行编码,请使用find和xargs:

find /home/noa/Desktop/codes -type f -print0 | \
xargs -0 sed --in-place "s/dbname=noa user=noa/dbname=masi user=masi"

(您可能也可以使用find的-exec或其他方法执行此操作,但我更喜欢xargs。)

这应该工作:

import re, os
import fnmatch
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("namelist.wps", 'a') as out:
               with open("namelist.wps", 'r') as readf:
                   for line in readf:
                       line = re.sub(r"dbname=noa user=noa", "dbname=masi user=masi", line)
                       out.write(line)

这就是我使用python查找和替换文件中字符串的方式。 这是一个简单的小函数,它将递归地在目录中搜索字符串并将其替换为字符串。 您还可以使用以下示例限制具有特定文件扩展名的文件。

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")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM