テキスト操作は、データ処理の中でも重要な作業の一つですね。
Python
を使えば、テキストファイルの読み込みが簡単に行えます。
しかし、条件を指定してテキストを読み込む際には、処理方法がわからなくなってしまうことも…
- 特定の行を読み込むにはどうすればいいの?
- 条件を満たす行を抽出する方法は?
- 読み込みを高速化する方法はある?
この記事では条件を指定して、テキストファイルから特定の行を読み込む方法を解説します。
特定の行を読み込む方法
特定の行番の行を読み込む基本的な方法としては、次の4つの方法を紹介します。
- 先にテキスト全体を読み込むパターン
- 指定行まで
for文
でスキップするパターン islice
で複数行を指定するパターン- ファイルをキャッシュに保存するパターン
各方法のメリット、デメリットは次の通りです。
方法 | メリット | デメリット |
---|---|---|
先に全体読み込み | ・簡単に特定の行を取得できる ・後から前の行に戻れる |
・ファイルが大きいとメモリ不足の可能性 |
指定行までスキップ | ・ファイルが大きくても処理可 ・対象行が前半にある処理が速い |
・対象行が後半にある場合 ・処理が遅い可能性がある |
islice で複数行 |
・ファイルが大きくても処理可 ・比較的安定して処理が速い |
・条件分岐不可 |
キャッシュ利用 | ・記述が極めて簡潔 ・テキストを何度も読むとき高速 |
・条件分岐不可 ・ファイルが大きいとメモリ不足の可能性 |
次のサンプルファイルを使用して、実行例を確認してみましょう。
text_lines = [ f"{n+1}行目\n" for n in range(1000000)]
with open("sample.txt", "w", encoding="utf-8") as f:
f.writelines(text_lines)
ファイルの中身は次のようになっています。
先にテキスト全体を読み込むパターン
テキストファイル全体を読み込んだ後に、特定の行を指定して抽出する方法です。
fileオブジェクト
の.readlines()
メソッドで、各行をリストとしてテキストを読み込めます。
lines = f.readlines()
:ファイル全体を読み込み
後はリストのインデックスで必要な行にアクセスすればOKです。
サンプルファイルで実行例を確認してみましょう。
with open("sample.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
lines[50000]
# 50001行目\n
lines[100000]
# '100001行目\n'
f.readlines()
は、行末の改行文字を削除してくれません。
改行文字が不要な場合は、.rstrip()
で削除しましょう。
with open("sample.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
lines[50000].rstrip()
# 50001行目
lines[100000].rstrip()
# '100001行目
- 【参考】ファイルの読み込み方法については次の記事で詳しく解説しています。
指定行までfor文でスキップするパターン
指定行までfor文
で読み飛ばすパターンです。
next()
関数を使用すると、file
オブジェクトを一行進めることができることを利用します。
next(f)
:ファイルオブジェクトを一行進める
サンプルファイルで実行例を確認してみましょう。
with open("sample.txt", "r", encoding="utf-8") as f:
for _ in range(100000):
next(f)
line = f.readline()
line
# '100001行目\n'
上記の例では、next()
関数で不要な行をスキップしています。
余計な読み込みはせずにシンプルにスキップして、少しでも高速化を目指しています。
file
は、ジェネレータとしても扱うと一行ずつ進むことを利用しています。
isliceで複数行を指定するパターン
file
のジェネレータの性質を利用すると、テキスト内の複数行を指定すること簡単にできます。
組み込みモジュールitertools
内のislice()
を使うと、特定の要素をスライス(抽出)できます。
islice(f, stop)
:0 → stop-1
までの要素islice(f, start, stop)
:start → stop-1
までの要素
ファイルの一部がスライスされるので、結果として特定の行のみをスライスできます。
サンプルコードで挙動を確認してみましょう。
from itertools import islice
# 3行目まで
with open("sample.txt", "r", encoding="utf-8") as f:
lines = islice(f, 3)
for line in lines:
print(line.rstrip())
# 1行目
# 2行目
# 3行目
# 1001行目~1003行目まで
with open("sample.txt", "r", encoding="utf-8") as f:
lines = islice(f, 1000, 1003)
for line in lines:
print(line.rstrip())
# 1001行目
# 1002行目
# 1003行目
メモリ使用量も少ないですし、実行速度も速いのこの方法が個人的にはおススメです。
ファイルをキャッシュに保存するパターン
linecache
モジュールを使用して、ファイルの内容をキャッシュする方法です。
キャッシュに保存するので、同じ行を何度も読み込む場合でも高速処理できる可能性が高いです。
getline("ファイル名", 行番号)
サンプルコードで挙動を確認してみましょう。
import linecache
line = linecache.getline('sample.txt', 1000)
print(line)
# 1000行目
# キャッシュの削除
# linecache.clearcache()
記述がシンプルでわかりやすい点も、この方法のメリットの一つです。
ただし、ファイルの内容をキャッシュしているため、大容量ファイルを扱う場合はメモリ使用量に注意が必要です。
キャッシュが不要になったら、.clearcache()
でキャッシュを削除しましょう。
条件を見たす行を抽出する方法
条件を見たす行を抽出する基本処理は、次のいずれかです。
- リスト内包表記で条件を指定
for文
で一行ずつ読み取り、if文
で条件分岐
いずれもPython
の基本文法ですね。次のように使い分けると良いと思います。
方法 | 特徴 | 使いやすい状況 |
---|---|---|
リスト内包表記 | 全行を処理 | テキストファイル全体を処理する場合 |
for文 で読み取り |
一行ずつ処理 | 途中で処理をやめる場合 |
リスト内包表記で条件を指定
テキスト全体をリストとして読み取り、リスト内包表記で条件を指定します。
lines = f.readlines()
target_lines = [line for line in lines if 条件文]
サンプルコードで実行例を確認してみましょう。
with open("sample.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
target_lines = [line for line in lines if line[0]=="1" ]
# ['1行目\n',
# '10行目\n',
# '11行目\n',
# ...
# '1000000行目\n']
上記の例では、一文字目が"1"
で始まる行を抽出しています。
正規表現を使用して、複雑な条件を指定することも可能です。
import re
# 1から始まり9で終わる数字のパターン
p = re.compile("1\d*9")
with open("sample.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
target_lines = [line for line in lines if p.match(line) ]
# ['19行目\n',
# '109行目\n',
# ...
# '199999行目\n']
正規表現のパターンについては、次の記事で詳しく解説しています。
for文で一行ずつ読み取り、if文で条件分岐
for文
で一行ずつ読み取り、条件に合った箇所で処理する方法です。
特別なテクニックはなく、基本的なプログラミングですね。
サンプルコードで実行例を確認してみましょう。
with open("sample.txt", "r", encoding="utf-8") as f:
for line in f:
if line.startswith("100"):
print(line)
break
"100行目"
必要な部分だけ読み込んで処理を終える場合などに便利ですね。
ただし、読み込み行数が多い場合は処理に時間がかかるようになります。
行番号で読み込んだり、キャッシュを利用したり、代替案がないか考えることもあると思います。
また、テキスト処理の条件分岐には正規表現を使うことも多いです。
サンプルコードで正規表現を使う例を確認してみましょう。
import re
# 1から始まり9で終わる数字のパターン
p = re.compile("1\d*9")
with open("sample.txt", "r", encoding="utf-8") as f:
for line in f:
if p.match(line):
break
line
# '19行目\n'
正規表現を使った検索、マッチについては、次の記事で詳しく解説しています。
正規表現で条件を見たす行を抽出
テキスト処理では正規表現のパターンを使用できるかどうかで、作業効率が大きく違ってきます。
複数行にまたがった条件を判定する場合には、正規表現は必須とも言えるでしょう。
例えば、次のようなテキストを考えてみましょう。
正規表現を使えば、各テーブルのデータを抽出するのも簡単です。
サンプルコードで実装例を見てみましょう。
import re
p = re.compile("TABLE(\d+)\s(.*?)/", re.DOTALL)
with open("tables.txt", "r", encoding="utf-8") as f:
text = f.read()
res = p.findall(text)
res
# [('1', '1 1\n2 4\n3 9\n'), ('2', '1 1\n2 8\n3 27\n')]
簡単にテーブル部分を抽出できましたね。
あとは必要に応じて成形して処理していけば良さそうです。
正規表現については、次の記事で詳しく解説しています。
オススメ|データ分析の勉強方法
今回はPythonでテキストファイルを読み込む方法について解説しました。
データ分析初心者の方にはこちらの記事もおススメです。
Pythonで作業の効率化を目指している方には、次の記事がおススメです。