답변:
이런 식으로해야한다고 생각합니다. 기본적으로 내용을 새 파일에 쓰고 이전 파일을 새 파일로 바꿉니다.
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)
mkstemp()
2 튜플을 반환하고 있음을 발견 (fh, abs_path) = fh, abs_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
여기서 일어나는 일은 :
print
진술은 원본 파일에 다시 작성됩니다.fileinput
더 많은 종과 휘파람이 있습니다. 예를 들어, 파일을 sys.args[1:]
명시 적으로 반복하지 않고도의 모든 파일을 자동으로 조작하는 데 사용할 수 있습니다 . Python 3.2부터는 with
명령문 에 사용하기 편리한 컨텍스트 관리자를 제공합니다 .
하지만 fileinput
일회용 스크립트를 위해 중대하다시피 그렇지 않은 매우 읽기 쉽고 잘 알고 있기 때문에, 나는 실제 코드에서 사용주의 될 것이다. 실제 (프로덕션) 코드에서는 프로세스를 명시 적으로 작성하여 코드를 읽을 수 있도록 몇 줄의 코드 만 더 사용하는 것이 좋습니다.
두 가지 옵션이 있습니다.
print(line, end='')
다음은 테스트되었으며 검색 및 바꾸기 패턴과 일치하는 다른 예입니다.
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.")
searchExp in line
아닙니다 line.replace
. 분명히 예제 사용이 잘못되었습니다.
if searchExp in line: line = line.replace(searchExp, replaceExpr)
당신은 쓸 수 있습니다 line = line.replace(searchExp, replaceExpr)
. 예외는 생성되지 않으며 라인은 변경되지 않습니다.
sys.stdout.write(line)
. 다시 감사합니다!
작동합니다 : (내부 편집)
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()
rb
하고 wb
속성 을 사용할 수 있습니다.
당신이 대체하는 일반적인 기능을 원하는 경우 어떤 다른 텍스트와 텍스트를, 이것은 당신이 정규식의의 팬이있어 특히 경우, 가능성이 갈 수있는 가장 좋은 방법입니다 :
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()
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')
아래에서 들여 쓰기를 제거하면 여러 줄로 검색되고 바뀝니다. 예를 들어 아래를 참조하십시오.
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)
file
동일한 이름의 미리 정의 된 클래스를 숨 깁니다.