IT

파이썬에서 파일의 줄을 검색하고 바꾸기

lottoking 2020. 3. 29. 09:15
반응형

파이썬에서 파일의 줄을 검색하고 바꾸기


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

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

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
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))
    #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 "%d: %s" % (fileinput.filelineno(), line),

여기서 일어나는 일은 :

  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 )

더 파이썬적인 방법은 아래 코드와 같은 컨텍스트 관리자를 사용하는 것입니다.

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)

전체 스 니펫은 여기에서 찾을 수 있습니다 .


새 파일을 작성하고 이전 파일에서 새 파일로 행을 복사 한 후 새 파일에 행을 쓰기 전에 바꾸기를 수행하십시오.


@Kiran의 대답을 확장하면 더 간결하고 Pythonic이라는 데 동의하며 UTF-8 읽기 및 쓰기를 지원하는 코덱을 추가합니다.

import codecs 

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 codecs.open(target_file_path, 'w', 'utf-8') as target_file:
        with codecs.open(source_file_path, 'r', 'utf-8') 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)

hamishmcn의 답변을 템플릿으로 사용하여 정규식과 일치하는 파일에서 줄을 검색하고 빈 문자열로 바꿀 수있었습니다.

import re 

fin = open("in.txt", 'r') # in file
fout = open("out.txt", 'w') # out file
for line in fin:
    p = re.compile('[-][0-9]*[.][0-9]*[,]|[-][0-9]*[,]') # pattern
    newline = p.sub('',line) # replace matching strings with empty string
    print newline
    fout.write(newline)
fin.close()
fout.close()

아래에서 들여 쓰기를 제거하면 여러 줄로 검색되고 바뀝니다. 예를 들어 아래를 참조하십시오.

def replace(file, pattern, subst):
    #Create temp file
    fh, abs_path = mkstemp()
    print fh, abs_path
    new_file = open(abs_path,'w')
    old_file = open(file)
    for line in old_file:
        new_file.write(line.replace(pattern, subst))
    #close temp file
    new_file.close()
    close(fh)
    old_file.close()
    #Remove original file
    remove(file)
    #Move new file
    move(abs_path, file)

fileinput 이전 답변에서 언급했듯이 매우 간단합니다.

import fileinput

def replace_in_file(file_path, search_text, new_text):
    with fileinput.input(file_path, inplace=True) as f:
        for line in f:
            new_line = line.replace(search_text, new_text)
            print(new_line, end='')

설명:

  • fileinput여러 파일을 사용할 수 있지만 처리되는 즉시 각 단일 파일을 닫는 것이 좋습니다. 그래서 성명서 file_path에서 단일 배치 with.
  • print문은 원본 파일로 전달 inplace=True되기 때문에 STDOUT이면 아무 것도 인쇄하지 않습니다 .
  • end=''print성명서 에서 중간 공백 새 줄을 제거하는 것입니다.

다음과 같이 사용할 수 있습니다 :

file_path = '/path/to/my/file'
replace_in_file(file_path, 'old-text', 'new-text')

참고 URL : https://stackoverflow.com/questions/39086/search-and-replace-a-line-in-a-file-in-python

반응형