Search and replace a line in a file in Python

前端 未结 13 1607
傲寒
傲寒 2020-11-21 07:40

I want to loop over the contents of a text file and do a search and replace on some lines and write the result back to the file. I could first load the whole file in memory

相关标签:
13条回答
  • 2020-11-21 08:11

    Based on the answer by Thomas Watnedal. However, this does not answer the line-to-line part of the original question exactly. The function can still replace on a line-to-line basis

    This implementation replaces the file contents without using temporary files, as a consequence file permissions remain unchanged.

    Also re.sub instead of replace, allows regex replacement instead of plain text replacement only.

    Reading the file as a single string instead of line by line allows for multiline match and replacement.

    import re
    
    def replace(file, pattern, subst):
        # Read contents from file as a single string
        file_handle = open(file, 'r')
        file_string = file_handle.read()
        file_handle.close()
    
        # Use RE package to allow for replacement (also allowing for (multiline) REGEX)
        file_string = (re.sub(pattern, subst, file_string))
    
        # Write contents to file.
        # Using mode 'w' truncates the file.
        file_handle = open(file, 'w')
        file_handle.write(file_string)
        file_handle.close()
    
    0 讨论(0)
  • 2020-11-21 08:15

    As lassevk suggests, write out the new file as you go, here is some example code:

    fin = open("a.txt")
    fout = open("b.txt", "wt")
    for line in fin:
        fout.write( line.replace('foo', 'bar') )
    fin.close()
    fout.close()
    
    0 讨论(0)
  • 2020-11-21 08:16

    The shortest way would probably be to use the fileinput module. For example, the following adds line numbers to a file, in-place:

    import fileinput
    
    for line in fileinput.input("test.txt", inplace=True):
        print('{} {}'.format(fileinput.filelineno(), line), end='') # for Python 3
        # print "%d: %s" % (fileinput.filelineno(), line), # for Python 2
    

    What happens here is:

    1. The original file is moved to a backup file
    2. The standard output is redirected to the original file within the loop
    3. Thus any print statements write back into the original file

    fileinput has more bells and whistles. For example, it can be used to automatically operate on all files in sys.args[1:], without your having to iterate over them explicitly. Starting with Python 3.2 it also provides a convenient context manager for use in a with statement.


    While fileinput is great for throwaway scripts, I would be wary of using it in real code because admittedly it's not very readable or familiar. In real (production) code it's worthwhile to spend just a few more lines of code to make the process explicit and thus make the code readable.

    There are two options:

    1. The file is not overly large, and you can just read it wholly to memory. Then close the file, reopen it in writing mode and write the modified contents back.
    2. The file is too large to be stored in memory; you can move it over to a temporary file and open that, reading it line by line, writing back into the original file. Note that this requires twice the storage.
    0 讨论(0)
  • 2020-11-21 08:19

    Here's another example that was tested, and will match search & replace patterns:

    import fileinput
    import sys
    
    def replaceAll(file,searchExp,replaceExp):
        for line in fileinput.input(file, inplace=1):
            if searchExp in line:
                line = line.replace(searchExp,replaceExp)
            sys.stdout.write(line)
    

    Example use:

    replaceAll("/fooBar.txt","Hello\sWorld!$","Goodbye\sWorld.")
    
    0 讨论(0)
  • 2020-11-21 08:19

    A more pythonic way would be to use context managers like the code below:

    from tempfile import mkstemp
    from shutil import move
    from os import remove
    
    def replace(source_file_path, pattern, substring):
        fh, target_file_path = mkstemp()
        with open(target_file_path, 'w') as target_file:
            with open(source_file_path, 'r') as source_file:
                for line in source_file:
                    target_file.write(line.replace(pattern, substring))
        remove(source_file_path)
        move(target_file_path, source_file_path)
    

    You can find the full snippet here.

    0 讨论(0)
  • 2020-11-21 08:22

    Create a new file, copy lines from the old to the new, and do the replacing before you write the lines to the new file.

    0 讨论(0)
提交回复
热议问题