YutaKaのPython教室

Python の文法やライブラリ、API、環境構築について画像・動画・ソースコード付きで徹底解説!

Python テキストファイルの任意の行を読み込む方法

テキスト操作は、データ処理の中でも重要な作業の一つですね。

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行目
  • 【参考】ファイルの読み込み方法については次の記事で詳しく解説しています。
≫Python テキストファイル読み込み・テキスト処理まとめ
Pythonでは簡単にテキストファイルを読み込むことができます。しかし、実際にテキストファイルを読み込もうとすると、次のような問題に直面することも…①ファイルの読み込みってどうやるんだっけ?②エンコーディングのエラーがでた!③テキストの出力方法にも種類があって、使い分けがよくわからない!そこで、この記事ではPythonでのテキストファイル読み込み、よく使うテキスト処理について、図解付きで徹底解説しています!
www.yutaka-note.com/entry/bf_openfile
 

指定行まで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()でキャッシュを削除しましょう。

条件を見たす行を抽出する方法

条件を見たす行を抽出する基本処理は、次のいずれかです。

  1. リスト内包表記で条件を指定
  2. for文で一行ずつ読み取り、if文で条件分岐

いずれもPythonの基本文法ですね。次のように使い分けると良いと思います。

方法 特徴 使いやすい状況
リスト内包表記 全行を処理 テキストファイル全体を処理する場合
for文で読み取り 一行ずつ処理 途中で処理をやめる場合

リスト内包表記で条件を指定

テキスト全体をリストとして読み取り、リスト内包表記で条件を指定します。

  1. lines = f.readlines()
  2. 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']

正規表現のパターンについては、次の記事で詳しく解説しています。

≫Python正規表現パターンを図解&サンプルで本当にわかりやすく解説
Pythonのreモジュールで正規表現パターンを作成する際に重要な3つのポイントを解説します。①特定の文字の繰り返しを指定 ②数値や文字、空白など条件による文字条件の指定 ③グループ化によるパターン内の特定部分の抽出
www.yutaka-note.com/entry/regex_01
 

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'

正規表現を使った検索、マッチについては、次の記事で詳しく解説しています。

≫Python 正規表現の検索を本当にわかりやすく解説
Pythonで正規表現を使用して、パターン検索する方法をわかりやすく解説しています。① 検索メソッド(関数)の実行方法② 各メソッドの紹介(単独検索search()、全体検索findallなど)③ 検索結果の出力であるMatchオブジェクトの内容
www.yutaka-note.com/entry/regex_02
 

正規表現で条件を見たす行を抽出

テキスト処理では正規表現のパターンを使用できるかどうかで、作業効率が大きく違ってきます。

複数行にまたがった条件を判定する場合には、正規表現は必須とも言えるでしょう。

例えば、次のようなテキストを考えてみましょう。

正規表現を使えば、各テーブルのデータを抽出するのも簡単です。

サンプルコードで実装例を見てみましょう。

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のreモジュールで正規表現パターンを作成する際に重要な3つのポイントを解説します。①特定の文字の繰り返しを指定 ②数値や文字、空白など条件による文字条件の指定 ③グループ化によるパターン内の特定部分の抽出
www.yutaka-note.com/entry/regex_01
 
≫Python 正規表現の検索を本当にわかりやすく解説
Pythonで正規表現を使用して、パターン検索する方法をわかりやすく解説しています。① 検索メソッド(関数)の実行方法② 各メソッドの紹介(単独検索search()、全体検索findallなど)③ 検索結果の出力であるMatchオブジェクトの内容
www.yutaka-note.com/entry/regex_02
 

オススメ|データ分析の勉強方法

今回はPythonでテキストファイルを読み込む方法について解説しました。

データ分析初心者の方にはこちらの記事もおススメです。

≫独学でデータ分析を勉強するオススメ学習本
独学でのpythonデータ分析勉強に役立ったおススメ書籍を紹介していきます。業務でそれなりにデータ分析を行えるまで、いろいろな試行錯誤をしてきましたが、もし自分が今ゼロから勉強する立場ならどうするのがいいのか考えてみました。以下では、入門書、個別モジュール用、実践用の3つの視点でおススメ本を紹介していきます。
www.yutaka-note.com/entry/data_analysis
 

Pythonで作業の効率化を目指している方には、次の記事がおススメです。

≫【レビュー】退屈なことはPythonにやらせよう | 単純作業は自動化
名著「退屈なことはPythonにやらせよう 」をレビュー!単純作業を自動化して、自分が本当にしたいことのために時間を確保していこう!所要時間やできるようになったことを紹介!この本を参考にして作成した、自作自動化スクリプトも紹介しています!
www.yutaka-note.com/entry/python_jido
 
≫【レビュー】Python自動処理 全部入り。 | 即効性重視!Pythonによる自動化事例集!
今回は、Pythonの作業自動処理の解説本『Python自動処理全部入り』をレビュー!この本は、特定の作業に特化した即効性の重視の自動化解説本です。よくある作業から自動化しやすい作業を抽出して、それらの自動化を集中的に解説した本という印象です。本の中に自分のニーズに合った自動化処理が見つかれば、その日からすぐ使える事例集のような印象です。
www.yutaka-note.com/entry/python_jido_zenbu