Pythonの正規表現マスターへ!re.findall()で文字列抽出を極める徹底解説
![]()
【Hiroki】
Yukiさん、こんにちは!
最近Pythonでテキスト処理を勉強しているんですけど、特定のパターンに当てはまる部分を「全部」抜き出したい時って、どうすればいいんでしょうか?
re.search()だと最初の一つしか見つからなくて、少し困っているんです。
![]()
【Yuki】
Hirokiくん、こんにちは。
文字列の中から条件に合うものをすべて見つけ出したいということですね。
ええと、そういう時にはPythonのreモジュールにあるre.findall()という関数を使うのが、一番の近道だと思います。
少し地味な機能に見えるかもしれませんが、データの抽出やクリーニングには欠かせない、とても大切なツールなんです。
![]()
【Hiroki】
re.findall()ですね!
やっぱり「全部(all)」を見つけるから、そういう名前なんですね。
具体的にどうやって使うのか、詳しく教えてもらえますか?
![]()
【Yuki】
はい、喜んで。
正規表現は少し複雑で、わたしもたまに「あれ?」って迷ってしまうことがあるんですけど……。
順を追って説明すれば、きっとHirokiくんも使いこなせるようになるはずです。
まずは、一番シンプルな使い方から見ていきましょう。
re.findall()の基本的な使い方
![]()
【Yuki】
re.findall()は、「パターン」に一致するすべての部分を「リスト」として返す関数です。
使い方はとてもシンプルで、re.findall(パターン, 対象の文字列)と書きます。
import re
text = "僕の電話番号は 080-1234-5678 で、友達のは 090-8765-4321 です。"
# 数字3桁-数字4桁-数字4桁のパターン
pattern = r"\d{3}-\d{4}-\d{4}"
results = re.findall(pattern, text)
print(results)
![]()
【Hiroki】
あ、本当だ!
実行結果が ['080-1234-5678', '090-8765-4321'] というリストで返ってきました。
これなら、いくつ見つかっても一気に取得できて便利ですね。
![]()
【Yuki】
そうなんです。
re.search()と違って、マッチオブジェクトを介さずに直接文字列のリストが手に入るのが、re.findall()の大きな特徴ですね。
もし、一つも一致するものが見つからなかった場合は、エラーにはならず、空のリスト [] が返ってきます。
これも、プログラムを書く上では扱いやすいポイントかもしれません。
![]()
【Hiroki】
なるほど。見つからなくてもプログラムが止まらないのは安心です。
ところで、パターンの前についている r って何でしたっけ?
![]()
【Yuki】
それは「生文字列(raw string)」という指定です。
正規表現では \(バックスラッシュ)をたくさん使うのですが、Pythonの普通の文字列だと \ は特別な意味(改行 \n など)を持ってしまいます。
r を付けることで、「この中の \ はそのまま正規表現の記号として扱ってね」とPythonに伝えることができるんです。
正規表現を書くときは、おまじないのように付けておくのが安全だと思います。
抽出の鍵を握る「メタ文字」と「特殊シーケンス」
![]()
【Hiroki】
パターンの中に書いてある \d とか {3} とか、これらをもっと使いこなせれば、いろんなものが抜き出せそうですね。
![]()
【Yuki】
ええ、その通りです。
よく使う記号(メタ文字)をいくつか紹介しますね。これらを組み合わせることで、抽出の幅がぐっと広がります。
\d: 数字(0-9)に一致します。\w: 英数字とアンダースコア(_)に一致します。\s: 空白文字(スペース、タブ、改行など)に一致します。+: 直前の文字が「1回以上」繰り返す場合に一致します。*: 直前の文字が「0回以上」繰り返す場合に一致します。.: 任意の1文字(改行を除く)に一致します。
![]()
【Hiroki】
例えば、「英単語だけを全部抜き出したい」時はどうすればいいんでしょう?
![]()
【Yuki】
その場合は、\w+ を使うといいかもしれません。
やってみましょうか。
import re
text = "Python is fun! I love programming."
# 1文字以上の英数字の塊を抽出
words = re.findall(r"\w+", text)
print(words)
![]()
【Hiroki】
実行すると ['Python', 'is', 'fun', 'I', 'love', 'programming'] になりました!
記号(! や .)が除外されて、言葉だけが綺麗に取れていますね。
![]()
【Yuki】
ふふ、上手くいきましたね。
このように、「何が何個続くか」を意識してパターンを作っていくのがコツです。
括弧 () を使う時の注意点:グループ化の挙動
![]()
【Hiroki】
Yukiさん、ちょっと試してみたんですけど、パターンの中に括弧 () を入れたら、結果が変わっちゃったんです。
どうしてでしょうか?
![]()
【Yuki】
あ……それは、re.findall() の少し「お節介」というか、独特な仕様に触れたのかもしれません。
実は re.findall() は、パターンの中にグループ化の括弧 () があると、その括弧の中身だけを抽出するという性質を持っているんです。
![]()
【Hiroki】
括弧の中身だけ?
![]()
【Yuki】
はい。例を見てみましょう。
例えば、日付の「年」の部分だけを括弧で囲ってみます。
import re
text = "2023/10/01, 2024/05/20"
# 年(4桁)だけをグループ化
pattern = r"(\d{4})/\d{2}/\d{2}"
results = re.findall(pattern, text)
print(results)
![]()
【Hiroki】
あ、結果が ['2023', '2024'] になりました!
全体の一致(2023/10/01)じゃなくて、括弧の中の4桁の数字だけが取れるんですね。
![]()
【Yuki】
そうなんです。もし括弧が2つ以上あると、今度はタプルのリストが返ってくるようになります。
# 年と月をそれぞれグループ化
pattern = r"(\d{4})/(\d{2})/\d{2}"
results = re.findall(pattern, text)
print(results)
# 結果: [('2023', '10'), ('2024', '05')]
![]()
【Hiroki】
なるほど!特定のパーツを分けて取りたい時にはすごく便利ですけど、知らないとびっくりしますね。
「全体もマッチさせたいけど、括弧を使いたい」時はどうすればいいんですか?
![]()
【Yuki】
その場合は、「非キャプチャグループ」というものを使います。
括弧の先頭に ?: を付けて (?:...) と書くと、「グループ化はするけれど、抽出の対象にはしない」という指定ができるんです。
少し複雑に見えるので、慣れるまでは大変かもしれませんけど……。
re.findall() でよく使われるフラグ
![]()
【Hiroki】
大文字と小文字を区別しないで探したい時はどうすればいいんでしょう?
例えば "python" も "Python" も両方見つけたい時です。
![]()
【Yuki】
それには、第3引数に「フラグ」を渡すといいですよ。
よく使われるのは re.IGNORECASE(または re.I)です。
import re
text = "Python, python, PYTHON!"
results = re.findall(r"python", text, re.IGNORECASE)
print(results)
# 結果: ['Python', 'python', 'PYTHON']
![]()
【Hiroki】
おぉ、一括で取れました!
これならパターンの書き方を工夫しすぎなくても大丈夫そうですね。
![]()
【Yuki】
はい。他にも、.(ドット)を改行にも一致させる re.DOTALL や、各行の先頭にマッチさせる re.MULTILINE などがあります。
でも、まずは re.IGNORECASE を覚えておけば、日常的な作業では十分だと思います。
大規模なデータには re.finditer()
![]()
【Hiroki】
あの、もしテキストがものすごく長かった場合でも、re.findall() を使って大丈夫でしょうか?
![]()
【Yuki】
それは、とても鋭い質問ですね。
re.findall() は見つけた結果をすべて一度にリストにしてメモリに読み込みます。
なので、数ギガバイトもあるような巨大なログファイルを解析しようとすると、メモリが足りなくなってしまうかもしれません。
![]()
【Hiroki】
やっぱりそうですよね。どうすればいいんですか?
![]()
【Yuki】
そういう時は、re.finditer() を使うのがおすすめです。
re.finditer() は、結果を一つずつ取り出せる「イテレータ」という形式で返してくれます。
import re
text = "sample1 sample2 sample3"
pattern = r"sample\d"
# findall の代わりに finditer を使う
for match in re.finditer(pattern, text):
print(f"見つかった文字列: {match.group()}, 位置: {match.start()}")
![]()
【Yuki】
これなら、一つずつ処理していくのでメモリに優しいですし、マッチした「場所(インデックス)」などの詳細な情報も取得できるんですよ。
「まずは手軽にリストが欲しいなら findall」、「大量のデータを丁寧に扱うなら finditer」と使い分けるのがスマートだと思います。
実戦的な例:メールアドレスの抽出
![]()
【Hiroki】
だんだん使い方がわかってきました!
最後に、何か実用的な例を教えてもらえませんか?
![]()
【Yuki】
そうですね。よくある例として、テキストの中からメールアドレスをすべて抜き出してみましょう。
少し複雑なパターンになりますが、これまでの知識を組み合わせれば読めるはずです。
import re
content = """
お問い合わせは support@example.com までお願いします。
担当者の連絡先は hiroki-test@pro.example.co.jp です。
"""
# メールアドレスの簡易的なパターン
# [英数字や記号]+ @ [英数字や記号]+ . [英数字]
email_pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
emails = re.findall(email_pattern, content)
print(emails)
![]()
【Hiroki】
うわっ、パターンが急に難しくなりましたね……!
でも、[] の中にある文字のどれかが +(1回以上)続いて、その後に @ が来て……と順番に見ていけば、なんとなく意味がわかります。
![]()
【Yuki】
すごいです、Hirokiくん。正解です!
正規表現は一見すると呪文のように見えますが、実はとても論理的に組み立てられているんです。
わたしも、最初は「こんなの無理……」って思っていたんですけど、一つ一つの記号の意味がわかると、パズルを解いているような感覚になれるかもしれません。
AIと正規表現の最新事情
![]()
【Hiroki】
最近はAIがコードを書いてくれることも多いですよね。
正規表現もAIにお任せしていいんでしょうか?
![]()
【Yuki】
ええ、もちろんです。
例えば、Googleの最新モデルである gemini-2.0-flash (※2024年末時点の最新)などは、非常に精度の高い正規表現を生成してくれます。
PythonでAIを使うなら、新しいライブラリの google-genai を使って、「このテキストから日付を抽出する正規表現を書いて」と頼むのも一つの手ですね。
![]()
【Hiroki】
AIにパターンを作ってもらって、それを re.findall() で使うっていう組み合わせですね!
![]()
【Yuki】
はい、それが今の時代の賢いプログラミングの進め方だと思います。
ただ、AIが作ったパターンが意図しないもの(例えば、不要な部分まで抜き出してしまうなど)である可能性もあります。
だからこそ、今回学んだ re.findall() の仕組みをHirokiくんが理解していることは、AIの出力をチェックするためにも、とても価値があることなんですよ。
まとめ
![]()
【Hiroki】
今日はありがとうございました、Yukiさん!
re.findall() について、すごくよくわかりました。
re.findall()は一致するすべてをリストで返す。- グループ化
()を使うと、その部分だけが抽出される。 - 大文字小文字を無視するには
re.IGNORECASEフラグを使う。 - 大きなデータには
re.finditer()を検討する。
これで合っていますか?
![]()
【Yuki】
完璧です!Hirokiくん、飲み込みが早くて助かります。
あ、最後に……正規表現の公式ドキュメントも、いつか目を通してみるといいかもしれません。
より深い使い方が載っていて、新しい発見があると思います。
![]()
【Yuki】
正規表現は、一度身につけると、テキスト処理の作業が何倍も速くなる魔法のような技術です。
もしまた、複雑なパターンに悩んだり、抽出が上手くいかなかったりした時は、いつでも相談してくださいね。
……わたしも、もっとスマートに教えられるように、夜な夜な練習しておきます。
![]()
【Hiroki】
心強いです!これからもよろしくお願いします、Yukiさん!
![]()
【Yuki】
はい、こちらこそ。
それでは、今日の講義はこれでおしまいにしましょう。
お疲れ様でした。
情報の根拠・参考リンク - Python documentation: re.findall - Python documentation: Regular Expression HOWTO - google-genai PyPI (Latest SDK info)
この記事では基礎を解説しましたが、実務においては「もっと複雑なデータを扱いたい」「独自のシステムに組み込みたい」といった、個別の課題に直面することも多いはずです。
「自分で書く時間は最小限に抑え、プロの品質でツールを完成させたい」という方は、ぜひ一度ご相談ください。
- 専門家の知見に基づいた、保守性の高いコード設計
- AIの専門家による、Gemini API等の最新AIを組み合わせた高度な自動化
- ChatGPT等が生成したコードのデバッグ・最適化
「教わる」だけでなく「形にする」パートナーとして、フリーランスエンジニアのmei_13が最短ルートでの解決をサポートします。


