ファイル内のテキストを検索して置換する方法は?


212

Python 3を使用してファイル内のテキストを検索および置換するにはどうすればよいですか?

これが私のコードです:

import os
import sys
import fileinput

print ("Text to search for:")
textToSearch = input( "> " )

print ("Text to replace it with:")
textToReplace = input( "> " )

print ("File to perform Search-Replace on:")
fileToSearch  = input( "> " )
#fileToSearch = 'D:\dummy1.txt'

tempFile = open( fileToSearch, 'r+' )

for line in fileinput.input( fileToSearch ):
    if textToSearch in line :
        print('Match Found')
    else:
        print('Match Not Found!!')
    tempFile.write( line.replace( textToSearch, textToReplace ) )
tempFile.close()


input( '\n\n Press Enter to exit...' )

入力ファイル:

hi this is abcd hi this is abcd
This is dummy text file.
This is how search and replace works abcd

上記の入力ファイルで「ram」を「abcd」に置き換えて検索すると、チャームとして機能します。しかし、その逆の場合、つまり「abcd」を「ram」に置き換えると、一部のジャンク文字が最後に残ります。

「abcd」を「ram」に置き換える

hi this is ram hi this is ram
This is dummy text file.
This is how search and replace works rambcd

「最後にいくつかのジャンクキャラクターが残っている」と言うと、もう少し具体的になりますか?
Burhan Khalid 2013年

私が得たものを出力して質問を更新しました。
Shriram 2013年

回答:


241

fileinput既にインプレース編集をサポートしています。stdoutこの場合、ファイルにリダイレクトします。

#!/usr/bin/env python3
import fileinput

with fileinput.FileInput(filename, inplace=True, backup='.bak') as file:
    for line in file:
        print(line.replace(text_to_search, replacement_text), end='')

13
end=''をすべきかという議論は何ですか?
egpbos 2014

18
lineすでに改行があります。endデフォルトでend=''は改行であり、print()関数は追加の改行を出力しません
jfs

11
fileinputを使用しないでください!代わりに、これを自分で行うコードを書くことを検討してください。sys.stdoutをリダイレクトすることは、特にfileinputのようにtry..finallyを使わずにリダイレクトする場合は、良い考えではありません。例外が発生した場合、stdoutが復元されない可能性があります。
2014

9
@craigds:間違っています。fileinput以下のためのツールではありません、すべてのジョブ(何もありません)が、それは多くの場合がある実装し、適切なツールの例は、sedPythonで様フィルタを。ドライバーを使って釘を叩かないでください。
jfs 2014

5
なんらかの理由で本当に stdoutをファイルにリダイレクトしたい場合は、それよりも上手く行うのは難しくありfileinputません(基本的に、try..finallyまたはcontextmanagerを使用して、後でstdoutを元の値に戻すようにします)。のソースコードfileinputは目を見張るほどひどいものであり、内部では本当に危険なことをいくつか行っています。もしそれが今日書かれていたら、それがstdlibに入れられたのではないかと私は非常に疑っています。
14

333

michaelb958で指摘されているように、残りのセクションが所定の位置に配置されないため、異なる長さのデータで所定の位置に置き換えることはできません。あるファイルから読み取り、別のファイルに書き込むことを提案している他のポスターには同意しません。代わりに、ファイルをメモリに読み込み、データを修正してから、別の手順で同じファイルに書き出します。

# Read in the file
with open('file.txt', 'r') as file :
  filedata = file.read()

# Replace the target string
filedata = filedata.replace('ram', 'abcd')

# Write the file out again
with open('file.txt', 'w') as file:
  file.write(filedata)

一度にメモリにロードするには大きすぎる大規模なファイルを処理する必要がない場合、またはファイルにデータを書き込む2番目のステップ中にプロセスが中断された場合にデータが失われる可能性を心配している場合を除きます。


5
with file = open(..):=意図は明らかですが、Python()は無効です。.replace()文字列は変更されない(不変)ため、戻り値を使用する必要があります。とにかく、複数の行にまたがるテキストを検索して置き換える必要がない限り、大きなファイルをサポートするコードはさらに単純になる可能性があります。
jfs

40
あなたはまったく正しい、そしてそれが-人々-インターネットで
恥ずかしがる

19
@JonasStein:いいえ、必要ありません。with声明は、自動的に文ブロックの最後にファイルを閉じます。
Jack Aidley

2
おもしろい@JackAidley。ご説明ありがとうございます。
Jonas Stein

4
@JackAidleyは、短く、シンプルで、簡単に使用および理解でき、多くの人々が抱えている実際の問題に対処しているためです(したがって、多くの人々が検索して、答えを見つけます)。
ベンバーデン2018

52

Jack Aidleyが投稿し、JF Sebastianが指摘したように、このコードは機能しません。

 # Read in the file
filedata = None
with file = open('file.txt', 'r') :
  filedata = file.read()

# Replace the target string
filedata.replace('ram', 'abcd')

# Write the file out again
with file = open('file.txt', 'w') :
  file.write(filedata)`

しかし、このコードは機能します(私はテストしました):

f = open(filein,'r')
filedata = f.read()
f.close()

newdata = filedata.replace("old data","new data")

f = open(fileout,'w')
f.write(newdata)
f.close()

この方法を使用すると、Python 3.3は書き込み用に開いたときにファイルを上書きするため、fileinとfileoutを同じファイルにすることができます。


9
違いはここにあると思います:filedata.replace( 'ram'、 'abcd')比較対象:newdata = filedata.replace( "old data"、 "new data") "with"ステートメントとは関係ありません
Diegomanas

5
1.- withステートメントを削除する理由 2.私の回答で述べたように、インfileinputプレースで動作できます。同じファイルのデータを置き換えることができます(内部で一時ファイルを使用します)。違いは、fileinputファイル全体をメモリにロードする必要がないことです。
jfs 2015年

8
ジャック・エイドリーの答えを再検討している他の人を救うために、この答え以降は修正されているので、これは冗長です(そして、よりきれいなwithブロックを失うために劣っています)。
クリス

46

このように交換できます

f1 = open('file1.txt', 'r')
f2 = open('file2.txt', 'w')
for line in f1:
    f2.write(line.replace('old_text', 'new_text'))
f1.close()
f2.close()

7

も使用できますpathlib

from pathlib2 import Path
path = Path(file_to_search)
text = path.read_text()
text = text.replace(text_to_search, replacement_text)
path.write_text(text)

Yuyaに感謝します。上記のソリューションはうまくいきました。注:元のファイル自体を置き換えるため、最初に元のファイルのバックアップを作成する必要があります。テキストを繰り返し置換したい場合は、以下のように最後の2行を追加し続けることができます。text = text.replace(text_to_search、replacement_text)path.write_text(text)
Nages

3

シングルwithブロックを使用すると、テキストを検索して置き換えることができます。

with open('file.txt','r+') as f:
    filedata = f.read()
    filedata = filedata.replace('abc','xyz')
    f.truncate(0)
    f.write(filedata)

1
seek書き込む前にファイルの先頭に移動するのを忘れました。truncateそれを行わないので、ファイル内にゴミがあります。
ur。

2

問題は、同じファイルの読み取りと書き込みに起因しています。fileToSearch書き込み用に開くのではなく、実際の一時ファイルを開き、完了して閉じたらtempFile、を使用os.renameして新しいファイルを上に移動しますfileToSearch


1
フレンドリーな参考情報(回答を自由に編集してください):根本的な原因は、ファイルの途中を短くできないことです。つまり、5文字を検索して3に置き換えると、検索された5文字の最初の3文字が置き換えられます。他の2つは削除できません。そのまま残ります。一時ファイルソリューションは、これらの「残った」文字を一時ファイルに書き出す代わりに削除することで削除します。
michaelb958--GoFundMonica 2013年

2

(pip install python-util)

from pyutil import filereplace

filereplace("somefile.txt","abcd","ram")

2番目のパラメーター(置き換えられるもの、たとえば「abcd」も正規表現にすることができます)
すべての出現箇所を置き換えます


私はこれでいくつかの悪い経験をしました(ファイルの最後にいくつかの文字を追加しました)ので、ワンライナーでいいのに、私はそれをお勧めできません。
Azrael3000

@ Azrael3000キャラクター追加?それが私に起こるのを見たことがありません。github.com/MisterL2/python-util
MisterL2

1

私の亜種、ファイル全体で一度に1つの単語。

それをメモリに読み込みます。

def replace_word(infile,old_word,new_word):
    if not os.path.isfile(infile):
        print ("Error on replace_word, not a regular file: "+infile)
        sys.exit(1)

    f1=open(infile,'r').read()
    f2=open(infile,'w')
    m=f1.replace(old_word,new_word)
    f2.write(m)

0

私はこれを行いました:

#!/usr/bin/env python3

import fileinput
import os

Dir = input ("Source directory: ")
os.chdir(Dir)

Filelist = os.listdir()
print('File list: ',Filelist)

NomeFile = input ("Insert file name: ")

CarOr = input ("Text to search: ")

CarNew = input ("New text: ")

with fileinput.FileInput(NomeFile, inplace=True, backup='.bak') as file:
    for line in file:
        print(line.replace(CarOr, CarNew), end='')

file.close ()

悲しい、しかしfileinput ではないDOEN仕事inplace=Trueutf-8
セルジオ

0

「!」のすべてのインスタンスを置き換えるために、Jayram Singhの投稿を少し変更しました 文字を、インスタンスごとに増分したい数字に変更します。1行に複数回出現する文字を変更して反復したい人には役立つかもしれないと思いました。それが誰かを助けることを願っています。PS-私はコーディングに非常に慣れていないので、私の投稿が何らかの形で不適切である場合は謝罪しますが、これは私にとってはうまくいきました。

f1 = open('file1.txt', 'r')
f2 = open('file2.txt', 'w')
n = 1  

# if word=='!'replace w/ [n] & increment n; else append same word to     
# file2

for line in f1:
    for word in line:
        if word == '!':
            f2.write(word.replace('!', f'[{n}]'))
            n += 1
        else:
            f2.write(word)
f1.close()
f2.close()

0
def word_replace(filename,old,new):
    c=0
    with open(filename,'r+',encoding ='utf-8') as f:
        a=f.read()
        b=a.split()
        for i in range(0,len(b)):
            if b[i]==old:
                c=c+1
        old=old.center(len(old)+2)
        new=new.center(len(new)+2)
        d=a.replace(old,new,c)
        f.truncate(0)
        f.seek(0)
        f.write(d)
    print('All words have been replaced!!!')

このコードは、意図した単語を置き換えます。唯一の問題は、ファイル全体を書き換えることです。ファイルが長すぎてプロセッサが処理できない場合、スタックする可能性があります。
Vinit Pillai

0

そのようです:

def find_and_replace(file, word, replacement):
  with open(file, 'r+') as f:
    text = f.read()
    f.write(text.replace(word, replacement))

あなたの回答が、この質問にすでに存在する他の回答を上回っていることを確認してください。
hongsy

これにより、ファイルの最後に置換後のテキストが追加されます。私の意見では、@ Jack Aidley aswerは、OPが単にstackoverflow.com/a/17141572/6875391
Kirill

-3
def findReplace(find, replace):

    import os 

    src = os.path.join(os.getcwd(), os.pardir) 

    for path, dirs, files in os.walk(os.path.abspath(src)):

        for name in files: 

            if name.endswith('.py'): 

                filepath = os.path.join(path, name)

                with open(filepath) as f: 

                    s = f.read()

                s = s.replace(find, replace) 

                with open(filepath, "w") as f:

                    f.write(s) 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.