note.nkmk.me

Pythonでファイル内の任意の文字列を含む行を抽出(grep的処理)

Date: 2018-05-22 / tags: Python, ファイル操作, 文字列操作

Pythonでテキストファイル内の任意の文字列を含む行を抽出する方法を説明する。いわゆるgrep的な処理。

  • 行を抽出する基本的な流れ
  • 行の中身を抽出
  • 行番号を抽出
  • 行番号と行の中身を抽出
  • 該当する最初の行のみ抽出
スポンサーリンク

行を抽出する基本的な流れ

テキストファイルから条件に応じて行を抽出する基本的な流れは以下の通り。

  • readlines()で各行を要素とするリストを取得
  • リストから条件に応じた行を抽出

以下、具体的な例を示す。

テキストファイルの中身をリストとして取得

以下のファイルを例とする。

path = 'data/src/sample_for_grep.txt'

with open(path) as f:
    print(f.read())
# XXX YYY ZZZ
# YYY
# aaa
# XXX
# ZZZ XXX
# xxx
source: grep_like.py

ファイルへのリンクはこちら。

ファイルを開き、readlines()で各行を要素とするリストを取得する。

with open(path) as f:
    lines = f.readlines()

print(lines)
# ['XXX YYY ZZZ\n', 'YYY\n', 'aaa\n', 'XXX\n', 'ZZZ XXX\n', 'xxx']

print(type(lines))
# <class 'list'>
source: grep_like.py

readlines()で取得できるリストは行末の改行文字\nを含んでいる。除去したい場合はリスト内包表記で各要素(各行)にstrip()メソッドを適用する。

lines_strip = [line.strip() for line in lines]
print(lines_strip)
# ['XXX YYY ZZZ', 'YYY', 'aaa', 'XXX', 'ZZZ XXX', 'xxx']
source: grep_like.py

行の中身を抽出

各行を要素とするリストからリスト内包表記で条件を満たす行のみを抽出する。

l_XXX = [line for line in lines_strip if 'XXX' in line]
print(l_XXX)
# ['XXX YYY ZZZ', 'XXX', 'ZZZ XXX']
source: grep_like.py

for文で出力。

for line in l_XXX:
    print(line)
# XXX YYY ZZZ
# XXX
# ZZZ XXX
source: grep_like.py

条件を満たす最初の行・最後の行はインデックスを指定すれば取得できる。

print(l_XXX[0])
# XXX YYY ZZZ

print(l_XXX[-1])
# ZZZ XXX
source: grep_like.py

なお、最初の行のみを抽出したい場合は、readlines()でリストを取得する必要はない。後述。

様々な条件

inだけでなく、文字列メソッドstartswith()(特定の文字で始まる)、endswith()(特定の文字で終わる)を使ったり、正規表現re.match()を使ったりできる。

l_XXX_start = [line for line in lines_strip if line.startswith('XXX')]
print(l_XXX_start)
# ['XXX YYY ZZZ', 'XXX']
source: grep_like.py

詳細は以下の記事を参照。

複数条件も可能。and(かつ)、or(または)で指定。

l_XXX_ZZZ_and = [line for line in lines_strip if ('XXX' in line) and ('ZZZ' in line)]
print(l_XXX_ZZZ_and)
# ['XXX YYY ZZZ', 'ZZZ XXX']
source: grep_like.py

大文字小文字を区別せず抽出したい場合は、複数条件を指定するよりも、対象文字列を小文字(または大文字)に変換してから判定するほうが楽。

l_XXX_xxx = [line for line in lines_strip if 'xxx' in line.lower()]
print(l_XXX_xxx)
# ['XXX YYY ZZZ', 'XXX', 'ZZZ XXX', 'xxx']
source: grep_like.py

行番号を抽出

条件を満たす行の行番号を抽出したい場合は組み込み関数enumerate()を使う。

l_XXX_i = [i for i, line in enumerate(lines_strip) if 'XXX' in line]
print(l_XXX_i)
# [0, 3, 4]
source: grep_like.py

条件の指定方法などは上の例と同じ。

行番号と行の中身を抽出

行番号と行の中身を合わせて抽出したい場合は以下のように書く。

l_XXX_both = [(i, line) for i, line in enumerate(lines_strip) if 'XXX' in line]
print(l_XXX_both)
# [(0, 'XXX YYY ZZZ'), (3, 'XXX'), (4, 'ZZZ XXX')]
source: grep_like.py

行番号と中身を分割することも可能。

l_i, l_str = list(zip(*l_XXX_both))

print(l_i)
# (0, 3, 4)

print(l_str)
# ('XXX YYY ZZZ', 'XXX', 'ZZZ XXX')
source: grep_like.py

該当する最初の行のみ抽出

条件に該当する最初の行だけを抽出したい場合は、これまでの例のようにreadlines()ですべての行をリスト化する必要はない。

ファイルオブジェクトをそのままfor文で回しファイルの先頭から一行ずつ文字列として取得し判定する。

with open(path) as f:
    for i, line in enumerate(f):
        if 'aaa' in line:
            break

print(i)
# 2

print(line)
# aaa
source: grep_like.py

末尾の改行文字\nを含んだ文字列に対する条件を指定する必要があるので、特に一致==を条件とする場合は注意。

with open(path) as f:
    for i, line in enumerate(f):
        if line == 'ZZZ XXX\n':
            break

print(i)
# 4

print(line)
# ZZZ XXX
source: grep_like.py

サイズが大きいファイルのヘッダーが何行目までかを確認したりするのに便利。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事