[python] 파이썬에서 파일에서 줄 검색 및 바꾸기

텍스트 파일의 내용을 반복하고 검색을 수행하고 일부 줄을 바꾸고 결과를 파일에 다시 씁니다. 먼저 전체 파일을 메모리에로드 한 다음 다시 쓸 수는 있지만 아마도 최선의 방법은 아닙니다.

다음 코드에서이를 수행하는 가장 좋은 방법은 무엇입니까?

f = open(file)
for line in f:
    if line.contains('foo'):
        newline = line.replace('foo', 'bar')
        # how to write this newline back to the file



답변

이런 식으로해야한다고 생각합니다. 기본적으로 내용을 새 파일에 쓰고 이전 파일을 새 파일로 바꿉니다.

from tempfile import mkstemp
from shutil import move, copymode
from os import fdopen, remove

def replace(file_path, pattern, subst):
    #Create temp file
    fh, abs_path = mkstemp()
    with fdopen(fh,'w') as new_file:
        with open(file_path) as old_file:
            for line in old_file:
                new_file.write(line.replace(pattern, subst))
    #Copy the file permissions from the old file to the new file
    copymode(file_path, abs_path)
    #Remove original file
    remove(file_path)
    #Move new file
    move(abs_path, file_path)


답변

가장 짧은 방법은 아마도 fileinput 모듈 을 사용하는 것입니다 . 예를 들어, 다음은 파일에 행 번호를 제자리에 추가합니다.

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

여기서 일어나는 일은 :

  1. 원본 파일은 백업 파일로 이동
  2. 표준 출력은 루프 내에서 원래 파일로 리디렉션됩니다
  3. 따라서 모든 print진술은 원본 파일에 다시 작성됩니다.

fileinput더 많은 종과 휘파람이 있습니다. 예를 들어, 파일을 sys.args[1:]명시 적으로 반복하지 않고도의 모든 파일을 자동으로 조작하는 데 사용할 수 있습니다 . Python 3.2부터는 with명령문 에 사용하기 편리한 컨텍스트 관리자를 제공합니다 .


하지만 fileinput일회용 스크립트를 위해 중대하다시피 그렇지 않은 매우 읽기 쉽고 잘 알고 있기 때문에, 나는 실제 코드에서 사용주의 될 것이다. 실제 (프로덕션) 코드에서는 프로세스를 명시 적으로 작성하여 코드를 읽을 수 있도록 몇 줄의 코드 만 더 사용하는 것이 좋습니다.

두 가지 옵션이 있습니다.

  1. 파일이 너무 크지 않으므로 메모리 전체를 읽을 수 있습니다. 그런 다음 파일을 닫고 쓰기 모드로 다시 연 다음 수정 된 내용을 다시 쓰십시오.
  2. 파일이 너무 커서 메모리에 저장되지 않습니다. 파일을 임시 파일로 옮길 수 있으며 파일을 한 줄씩 읽고 원본 파일에 다시 쓸 수 있습니다. 이를 위해서는 두 배의 스토리지가 필요합니다.

답변

다음은 테스트되었으며 검색 및 바꾸기 패턴과 일치하는 다른 예입니다.

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)

사용 예 :

replaceAll("/fooBar.txt","Hello\sWorld!$","Goodbye\sWorld.")


답변

작동합니다 : (내부 편집)

import fileinput

# Does a list of files, and
# redirects STDOUT to the file in question
for line in fileinput.input(files, inplace = 1):
      print line.replace("foo", "bar"),


답변

Thomas Watnedal의 답변을 기반으로합니다. 그러나 이것은 원래 질문의 행간 부분에 정확하게 대답하지는 않습니다. 이 기능은 여전히 ​​라인 단위로 교체 할 수 있습니다

이 구현은 임시 파일을 사용하지 않고 파일 내용을 대체하므로 파일 권한이 변경되지 않습니다.

또한 replace 대신 re.sub를 사용하면 일반 텍스트 대체 대신 정규식 대체를 허용합니다.

파일을 줄 단위 대신 단일 문자열로 읽으면 여러 줄 일치 및 교체가 가능합니다.

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


답변

lassevk가 제안한 것처럼 새 파일을 작성하면 다음과 같은 예제 코드가 있습니다.

fin = open("a.txt")
fout = open("b.txt", "wt")
for line in fin:
    fout.write( line.replace('foo', 'bar') )
fin.close()
fout.close()


답변

당신이 대체하는 일반적인 기능을 원하는 경우 어떤 다른 텍스트와 텍스트를, 이것은 당신이 정규식의의 팬이있어 특히 경우, 가능성이 갈 수있는 가장 좋은 방법입니다 :

import re
def replace( filePath, text, subs, flags=0 ):
    with open( filePath, "r+" ) as file:
        fileContents = file.read()
        textPattern = re.compile( re.escape( text ), flags )
        fileContents = textPattern.sub( subs, fileContents )
        file.seek( 0 )
        file.truncate()
        file.write( fileContents )