Python の re.findall() 関数
re.findall() 関数でマッチした全ての文字列を取得する
正規表現を使って、マッチした部分の文字列を取得したいとします。
「Python で正規表現を使う基本的な例」で紹介したように、 re.match() や re.search() では、 正規表現のパターンとフラグを受け取りマッチオブジェクトを返します。マッチした文字列を取得するには、 グループを使ってキャプチャし、 group() を使って、マッチオブジェクトからキャプチャした文字列を取り出しました。
re.findall() 関数では、マッチオブジェクトを返すのではなく、マッチした文字列のリストを返します。 キャプチャのための () を書く必要はありません。
例えば、次のような簡単な旅行日程メモ (文字列) があるとします。
6/10/2019: NH106 HND to LAX 6/25/2019: NH105 LAX to HND
この中から、便名を取り出して表示みましょう。
NH106 や NH105 は航空機の便名。 HND や LAX は空港のコードで、それぞれ羽田空港とロサンゼルス国際空港です。
re.findall() はマッチした文字列のリストを返します。マッチしない場合は、 空のリスト [] を返します。
よって、for 文と組み合わせて次のように書くことができます。
import re
s = """
6/10/2019: NH106 HND to LAX
6/25/2019: NH105 LAX to HND
"""
for m in re.findall(r'(?!\d{2})[A-Z0-9]{2}\d{1,4}', s):
print(m)
実行結果は次の通りです。
NH106
NH105
マッチしたかどうかチェックしたり、グループを指定する必要もないので re.search() などよりも単純になっています。
re.findall() 関数に渡すパターンに () を含むと Tuple のリストが返る
re.findall() では、パターンに () が含まれる場合は文字列のタプルのリストが返ります。
パターンにグループを含んでみましょう。名前: に続いて、電話番号らしきものがあったときにとってくるような場合を考えてみましょう。
import re
s = """
Mike:123-456-7890
John: 098.765.4321
Jane: 8085553333
"""
for m in re.findall(r'(\w+):[ \t]*(\d{3})[.-]?(\d{3})[.-]?(\d{4})', s):
print(m)
実行結果は次の通りです。
('Mike', '123', '456', '7890')
('John', '098', '765', '4321')
('Jane', '808', '555', '3333')
このように、 re.findall() を使うととても簡単にマッチした部分を取り出すことができます。