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

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

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

sample_for_grep.txt

ファイルを開き、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'>

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

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

行の中身を抽出

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

l_XXX = [line for line in lines_strip if 'XXX' in line]
print(l_XXX)
# ['XXX YYY ZZZ', 'XXX', 'ZZZ XXX']

for文で出力。

for line in l_XXX:
    print(line)
# XXX YYY ZZZ
# XXX
# ZZZ XXX

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

print(l_XXX[0])
# XXX YYY ZZZ

print(l_XXX[-1])
# ZZZ XXX

なお、最初の行のみを抽出したい場合は、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']

詳細は

複数条件もできます。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']

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

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']

行番号を抽出

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

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

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

行番号と行の中身を抽出

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

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')]

行番号と中身を分割することもできます。

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

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

print(l_str)
# ('XXX YYY ZZZ', 'XXX', 'ZZZ XXX')

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

条件に該当する最初の行だけを抽出したい場合は、これまでの例のようにreadlines()ですべての行をリスト化する必要はない。 ファイルオブジェクトをそのままfor文で回しファイルの先頭から一行ずつ文字列として取得し判定します。

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

print(i)
# 2

print(line)
# aaa

末尾の改行文字\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

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

Last Updated: 6/26/2019, 10:34:03 PM