re.findall() / re.finditer()
| 対応: | Python 2(2000) |
|---|
正規表現を使って文字列からパターンに一致する全ての部分を取り出す関数です。『re.findall()』はリストを返し、『re.finditer()』はマッチオブジェクトのイテレータを返します。
構文
import re
# パターンに一致する全ての文字列をリストで返す
マッチリスト = re.findall(パターン, 文字列)
# パターンに一致する全てのマッチオブジェクトをイテレータで返す
for m in re.finditer(パターン, 文字列):
print(m.group())
print(m.start(), m.end()) # マッチした位置も取得できる
関数一覧
| 関数 | 概要 |
|---|---|
| re.findall(pattern, string) | パターンに一致する全ての文字列をリストで返します。キャプチャグループがある場合はグループの内容のリストを返します。マッチが1つもない場合は空のリストを返します。 |
| re.finditer(pattern, string) | パターンに一致する全てのマッチオブジェクトをイテレータで返します。各オブジェクトからマッチ位置やグループを取得できます。 |
サンプルコード
findall_basic.py
import re
text = '商品A: 1200円、商品B: 850円、商品C: 3000円'
prices = re.findall(r'\d+', text)
print(prices)
total = sum(int(p) for p in prices)
print(f'合計: {total}円')
実行すると次のように出力されます。
python3 findall_basic.py ['1200', '850', '3000'] 合計: 5050円
findall_groups.py
import re
html = '<a href="https://example.com">サイト1</a> <a href="https://test.jp">サイト2</a>'
urls = re.findall(r'href="([^"]+)"', html)
print(urls)
log = '2025-04-01 ERROR: timeout\n2025-04-02 INFO: started\n2025-04-03 ERROR: crash'
errors = re.findall(r'(\d{4}-\d{2}-\d{2}) (ERROR): (.+)', log)
print(errors)
実行すると次のように出力されます。
python3 findall_groups.py
['https://example.com', 'https://test.jp']
[('2025-04-01', 'ERROR', 'timeout'), ('2025-04-03', 'ERROR', 'crash')]
finditer_example.py
import re
text2 = 'ioriとkyoとterry'
for m in re.finditer(r'[a-z]+', text2):
print(f'{m.group()} (位置: {m.start()}-{m.end()})')
big_text = 'A1 B2 C3 D4 E5 ' * 10000
count = sum(1 for _ in re.finditer(r'[A-Z]\d', big_text))
print(f'マッチ数: {count}')
実行すると次のように出力されます。
python3 finditer_example.py iori (位置: 0-4) kyo (位置: 5-8) terry (位置: 9-14) マッチ数: 50000
よくあるミス
よくあるミス1: キャプチャグループの有無で戻り値の型が変わる
グループなし→文字列のリスト、グループ1つ→グループ内容の文字列リスト、グループ複数→タプルのリストとなります。意図しない型になっていないか注意が必要です。
import re text = '電話: 03-1234-5678' result = re.findall(r'(\d+)-(\d+)-(\d+)', text) print(result[0])
次のように記述します。
import re
text = '電話: 03-1234-5678'
result = re.findall(r'(\d+)-(\d+)-(\d+)', text)
area, exchange, number = result[0]
print(f'{area}-{exchange}-{number}')
よくあるミス2: 重複マッチが取得できない
前のマッチが終わった位置から次の検索が始まるため、重複するパターンは取得できません。重複マッチが必要な場合は先読みアサーション(lookahead)を使えます。
import re text = 'aaaa' result = re.findall(r'aa', text) print(result)
次のように記述します。
import re text = 'aaaa' result = re.findall(r'(?=(aa))', text) print(result)
概要
『re.findall()』はシンプルにマッチした文字列のリストが欲しい場合に使います。キャプチャグループの有無によって戻り値の形式が変わります。グループがない場合は文字列のリスト、グループが1つある場合はグループの文字列のリスト、グループが複数ある場合はタプルのリストになります。
『re.finditer()』はマッチオブジェクトのイテレータを返すため、マッチした文字列だけでなく位置情報(『start()』・『end()』)やキャプチャグループも同時に取得できます。また結果をすべてメモリに保持せずに1件ずつ処理するため、大量のマッチがある場合は『findall()』よりもメモリ効率が良いです。
パターンに一致する部分が重複する場合、前のマッチが終わった位置から次の検索が始まるため、重複マッチは取得できません。重複マッチが必要な場合は先読みアサーション(lookahead)を使えます。
単一マッチの検索は『re.match() / re.search() / re.fullmatch()』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。