python实现的用于搜索文件并进行内容替换的类实例

1310次阅读  |  发布于5年以前

本文实例讲述了python实现的用于搜索文件并进行内容替换的类。分享给大家供大家参考。具体实现方法如下:


    #!/usr/bin/python -O
    # coding: UTF-8
    """
    -replace string in files (recursive)
    -display the difference.
    v0.2
     - search_string can be a re.compile() object -> use re.sub for replacing
    v0.1
     - initial version
      Useable by a small "client" script, e.g.:
    -------------------------------------------------------------------------------
    #!/usr/bin/python -O
    # coding: UTF-8
    import sys, re
    #sys.path.insert(0,"/path/to/git/repro/") # Please change path
    from replace_in_files import SearchAndReplace
    SearchAndReplace(
      search_path = "/to/the/files/",
      # e.g.: simple string replace:
      search_string = 'the old string',
      replace_string = 'the new string',
      # e.g.: Regular expression replacing (used re.sub)
      #search_string = re.compile('{% url (.*?) %}'),
      #replace_string = "{% url '\g<1>' %}",
      search_only = True, # Display only the difference
      #search_only = False, # write the new content
      file_filter=("*.py",), # fnmatch-Filter
    )
    -------------------------------------------------------------------------------
    :copyleft: 2009-2011 by Jens Diemer
    """
    __author__ = "Jens Diemer"
    __license__ = """GNU General Public License v3 or above -
     http://www.opensource.org/licenses/gpl-license.php"""
    __url__ = "http://www.jensdiemer.de"
    __version__ = "0.2"
    import os, re, time, fnmatch, difflib
    # FIXME: see http://stackoverflow.com/questions/4730121/cant-get-an-objects-class-name-in-python
    RE_TYPE = type(re.compile(""))
    class SearchAndReplace(object):
      def __init__(self, search_path, search_string, replace_string,
                        search_only=True, file_filter=("*.*",)):
        self.search_path = search_path
        self.search_string = search_string
        self.replace_string = replace_string
        self.search_only = search_only
        self.file_filter = file_filter
        assert isinstance(self.file_filter, (list, tuple))
        # FIXME: see http://stackoverflow.com/questions/4730121/cant-get-an-objects-class-name-in-python
        self.is_re = isinstance(self.search_string, RE_TYPE)
        print "Search '%s' in [%s]..." % (
          self.search_string, self.search_path
        )
        print "_" * 80
        time_begin = time.time()
        file_count = self.walk()
        print "_" * 80
        print "%s files searched in %0.2fsec." % (
          file_count, (time.time() - time_begin)
        )
      def walk(self):
        file_count = 0
        for root, dirlist, filelist in os.walk(self.search_path):
          if ".svn" in root:
            continue
          for filename in filelist:
            for file_filter in self.file_filter:
              if fnmatch.fnmatch(filename, file_filter):
                self.search_file(os.path.join(root, filename))
                file_count += 1
        return file_count
      def search_file(self, filepath):
        f = file(filepath, "r")
        old_content = f.read()
        f.close()
        if self.is_re or self.search_string in old_content:
          new_content = self.replace_content(old_content, filepath)
          if self.is_re and new_content == old_content:
            return
          print filepath
          self.display_plaintext_diff(old_content, new_content)
      def replace_content(self, old_content, filepath):
        if self.is_re:
          new_content = self.search_string.sub(self.replace_string, old_content)
          if new_content == old_content:
            return old_content
        else:
          new_content = old_content.replace(
            self.search_string, self.replace_string
          )
        if self.search_only != False:
          return new_content
        print "Write new content into %s..." % filepath,
        try:
          f = file(filepath, "w")
          f.write(new_content)
          f.close()
        except IOError, msg:
          print "Error:", msg
        else:
          print "OK"
        print
        return new_content
      def display_plaintext_diff(self, content1, content2):
        """
        Display a diff.
        """
        content1 = content1.splitlines()
        content2 = content2.splitlines()
        diff = difflib.Differ().compare(content1, content2)
        def is_diff_line(line):
          for char in ("-", "+", "?"):
            if line.startswith(char):
              return True
          return False
        print "line | text\n-------------------------------------------"
        old_line = ""
        in_block = False
        old_lineno = lineno = 0
        for line in diff:
          if line.startswith(" ") or line.startswith("+"):
            lineno += 1
          if old_lineno == lineno:
            display_line = "%4s | %s" % ("", line.rstrip())
          else:
            display_line = "%4s | %s" % (lineno, line.rstrip())
          if is_diff_line(line):
            if not in_block:
              print "..."
              # Display previous line
              print old_line
              in_block = True
            print display_line
          else:
            if in_block:
              # Display the next line aber a diff-block
              print display_line
            in_block = False
          old_line = display_line
          old_lineno = lineno
        print "..."
    if __name__ == "__main__":
      SearchAndReplace(
        search_path=".",
        # e.g.: simple string replace:
        search_string='the old string',
        replace_string='the new string',
        # e.g.: Regular expression replacing (used re.sub)
        #search_string  = re.compile('{% url (.*?) %}'),
        #replace_string = "{% url '\g<1>' %}",
        search_only=True, # Display only the difference
    #    search_only   = False, # write the new content
        file_filter=("*.py",), # fnmatch-Filter
      )

希望本文所述对大家的Python程序设计有所帮助。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8