web-dev-qa-db-ja.com

Pythonを使用してファイル内の特定の行を削除する

ニックネームでいっぱいのテキストファイルがあるとします。 Pythonを使用して、このファイルから特定のニックネームを削除するにはどうすればよいですか?

115
SourD

まず、ファイルを開き、ファイルからすべての行を取得します。次に、ファイルを書き込みモードで再度開き、削除する行を除き、行を書き戻します。

with open("yourfile.txt", "r") as f:
    lines = f.readlines()
with open("yourfile.txt", "w") as f:
    for line in lines:
        if line.strip("\n") != "nickname_to_delete":
            f.write(line)

ファイルが改行文字で終了していない場合、最後のlineも比較しないため、比較でstrip("\n")改行文字を使用する必要があります。

162
houbysoft

単一のオープンのみでこの問題の解決策:

with open("target.txt", "r+") as f:
    d = f.readlines()
    f.seek(0)
    for i in d:
        if i != "line you want to remove...":
            f.write(i)
    f.truncate()

このソリューションは、ファイルをr/wモード(「r +」)で開き、f-pointerをリセットするためにシークを使用し、最後の書き込み後に切り捨ててすべてを削除します。

81
Lother

リストにすべてを保存してファイルを再度開いて書き込むのではなく、最良かつ最速のオプションは、ファイルを別の場所に再書き込みすることです。

with open("yourfile.txt", "r") as input:
    with open("newfile.txt", "w") as output: 
        for line in input:
            if line.strip("\n") != "nickname_to_delete":
                output.write(line)

それでおしまい! 1つのループと1つだけで同じことができます。それははるかに高速になります。

21
Barnabe

これは、@ Lotherの答えからの「分岐」です(これは正しい答えと見なされるべきです)。


このようなファイルの場合:

$ cat file.txt 
1: october Rust
2: november rain
3: december snow

Lotherのソリューションからのこの分岐は正常に機能します。

#!/usr/bin/python3.4

with open("file.txt","r+") as f:
    new_f = f.readlines()
    f.seek(0)
    for line in new_f:
        if "snow" not in line:
            f.write(line)
    f.truncate()

改善点:

  • f.close()の使用を破棄するwith open
  • 現在の行に文字列が存在しないかどうかを評価するためのif/elseをより明確に
17
ivanleoncz

最初のパスで行を読み取り、2番目のパスで変更を行う(特定の行を削除する)問題は、ファイルサイズが大きい場合、RAMが不足することです。代わりに、行を1行ずつ読み取り、別のファイルに書き込むことで、不要な行を削除することをお勧めします。 12〜50 GBのファイルでこのアプローチを実行しましたが、RAMの使用量はほぼ一定のままです。 CPUサイクルのみが進行中の処理を示します。

4
Kingz

Linuxを使用している場合は、次のアプローチを試すことができます。
animal.txtという名前のテキストファイルがあるとします。

$ cat animal.txt  
dog
pig
cat 
monkey         
elephant  

最初の行を削除します。

>>> import subprocess
>>> subprocess.call(['sed','-i','/.*dog.*/d','animal.txt']) 

それから

$ cat animal.txt
pig
cat
monkey
elephant
3
Ren

ファイルをリストに読み込んだら、リストを反復処理して、削除したいニックネームを探すことができると思います。追加のファイルを作成せずに非常に効率的に実行できますが、結果をソースファイルに書き戻す必要があります。

これをどのように行うかを以下に示します。

import, os, csv # and other imports you need
nicknames_to_delete = ['Nick', 'Stephen', 'Mark']

nicknames.csvには次のようなデータが含まれていると仮定しています。

Nick
Maria
James
Chris
Mario
Stephen
Isabella
Ahmed
Julia
Mark
...

次に、ファイルをリストにロードします。

 nicknames = None
 with open("nicknames.csv") as sourceFile:
     nicknames = sourceFile.read().splitlines()

次に、リストを繰り返し処理して、削除する入力を一致させます。

for nick in nicknames_to_delete:
     try:
         if nick in nicknames:
             nicknames.pop(nicknames.index(nick))
         else:
             print(nick + " is not found in the file")
     except ValueError:
         pass

最後に、結果をファイルに書き戻します。

with open("nicknames.csv", "a") as nicknamesFile:
    nicknamesFile.seek(0)
    nicknamesFile.truncate()
    nicknamesWriter = csv.writer(nicknamesFile)
    for name in nicknames:
        nicknamesWriter.writeRow([str(name)])
nicknamesFile.close()
2
A Malik

ファイル全体をメモリに保存するのは良い解決策ではありませんが、最近では誰もが大量のメモリを持っていることを知っていますが、ファイルが数GBのログか何かを検討してください。

最初のファイルなどを削除するよりも、新しいファイルに1行ずつコピーする方が良い方法です

2
user3063349

この回答で説明されているように、fileinputアプローチが好きでした: テキストファイルからの行の削除(python)

たとえば、空の行が含まれているファイルがあり、空の行を削除したい場合、次のように解決します。

import fileinput
import sys
for line_number, line in enumerate(fileinput.input('file1.txt', inplace=1)):
    if len(line) > 1:
            sys.stdout.write(line)

注:私の場合、空の行の長さは1でした。

2
Deep

おそらく、あなたはすでに正しい答えを得ていますが、これは私のものです。リストを使用してフィルタリングされていないデータを収集する代わりに(readlines()メソッドが行うこと)、2つのファイルを使用します。 1つはメインデータを保持するため、もう1つは特定の文字列を削除するときにデータをフィルタリングするためです。コードは次のとおりです。

main_file = open('data_base.txt').read()    # your main dataBase file
filter_file = open('filter_base.txt', 'w')
filter_file.write(main_file)
filter_file.close()
main_file = open('data_base.txt', 'w')
for line in open('filter_base'):
    if 'your data to delete' not in line:    # remove a specific string
        main_file.write(line)                # put all strings back to your db except deleted
    else: pass
main_file.close()

これがあなたの役に立つことを願っています! :)

1
andrii1986

一般的に、できません。 (少なくとも変更点から最後まで)ファイル全体を再度書き込む必要があります。

いくつかの特定のケースでは、これよりも良いことができます-

すべてのデータ要素が同じ長さで、特定の順序でなく、削除するもののオフセットがわかっている場合、削除するものの上に最後の項目をコピーし、最後の項目の前にファイルを切り捨てることができます;

または、データチャンクを「this is bad data、skip it」値で上書きするか、保存されたデータ要素に「this item has deleted」フラグを保持して、ファイルを変更せずに削除済みとしてマークすることができます。

これはおそらく、短いドキュメント(100 KB未満の場合)では過剰です。

1
Hugh Bothwell

ファイルの行をリストに保存してから、削除したい行をリストから削除し、残りの行を新しいファイルに書き込みます

with open("file_name.txt", "r") as f:
    lines = f.readlines() 
    lines.remove("Line you want to delete\n")
    with open("new_file.txt", "w") as new_f:
        for line in lines:        
            new_f.write(line)
0

ファイルから行を削除する他の方法を次に示します。

src_file = zzzz.txt
f = open(src_file, "r")
contents = f.readlines()
f.close()

contents.pop(idx) # remove the line item from list, by line number, starts from 0

f = open(src_file, "w")
contents = "".join(contents)
f.write(contents)
f.close()
0
ungalcrys

私はfileinputと 'inplace'メソッドを使用するこのメソッドが好きです:

import fileinput
for line in fileinput.input(fname, inplace =1):
    line = line.strip()
    if not 'UnwantedWord' in line:
        print(line)

それは他の答えよりも少し冗長で、十分に高速です

0
Ru887321

reライブラリを使用できます

完全なtxtファイルをロードできると仮定します。次に、不要なニックネームのリストを定義し、空の文字列「」で置き換えます。

# Delete unwanted characters
import re

# Read, then decode for py2 compat.
path_to_file = 'data/nicknames.txt'
text = open(path_to_file, 'rb').read().decode(encoding='utf-8')

# Define unwanted nicknames and substitute them
unwanted_nickname_list = ['SourDough']
text = re.sub("|".join(unwanted_nickname_list), "", text)
0
mrk