午前2時、監視システムからの通知でスマホが激しく震えた。私は飛び起き、コンソールを開いて惨状を目の当たりにした。2GBを超えるログファイルが、数千行もの Connection Timeout エラーで埋め尽くされていた。今すぐやるべきことは、スパムリクエストを送っているIPアドレスのリストを抽出して即座に遮断することだ。
通常の grep コマンドを使ったり、目視で確認したりするのは、この状況では不可能だ。そこで救世主となるのが Regex(Regular Expression – 正規表現)である。Pythonを学んでいて、Regexが無意味な記号의 羅列に見えるかもしれないが、心配はいらない。この記事でその「暗号」を解読していこう。
クイックスタート:5分で2GB의 ログファイルを処理する
理論だけでRegexを学ぼうとすると、頭が痛くなるだけだ。まずは、乱雑なデータからIPアドレスを抽出するという実戦的な課題から始めよう。
import re
log_data = """
192.168.1.1 - - [12/Apr/2026:02:00:01] "GET /index.html HTTP/1.1" 200
10.0.0.50 - - [12/Apr/2026:02:00:02] "POST /login HTTP/1.1" 403
Invalid IP 999.999.999.999 but 172.16.254.1 is okay.
"""
# IPアドレス(x.x.x.x形式)を検索するシンプルなパターン
ip_pattern = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
ips = re.findall(ip_pattern, log_data)
print(f"{len(ips)} 個のIPアドレスが見つかりました: {ips}")
module re を使ったわずか2行のコードで、データの整理が完了した。ここで、\d は数字を表し、{1,3} は1回から3回の繰り返しを意味する。\. は、単なる任意の1文字ではなく、実際の「ドット(.)」であることをコンピュータに理解させるためのものだ。
解説:Regexを構成するパーツ
Regexを一つの塊として見るのではなく、レゴブロックのパーツのように考えてみよう。ルールを理解すれば、Regexを「読む」ことは新しい言語を学ぶのと同じくらい自然なことになる。
1. メタ文字 (Metacharacters)
.(ドット): 任意の1文字に一致する。例えばa.cは “abc”、”a1c”、”a#c” などに一致する。^と$: 行の先頭と末尾を示す。\d: 数字 (0-9) を探す。\w: 英数字またはアンダースコアを探す.\s: 空白文字またはタブを探す。
2. 量指定子 (Quantifiers) — 何回繰り返すか?
これはパターンを短縮するための秘訣だ:
*: 0回以上(無限)の繰り返し。+: 1回以上の繰り返し。?: あってもなくてもよい(0回または1回)。{n,m}: n回からm回の範囲での繰り返し。
3. グループ化と論理演算
[abc]: a、b、またはcのいずれかを探す。(abc): 処理や抽出のためにグループ化する。|: OR演算(「または」)。例えばpython|javaは両方の言語を検索する。
高度なテクニック:データの抽出 (Capture Groups)
単に文字列が一致するかどうかを確認するだけではない場合もある。例えば、5,000件の顧客メールリストから、レポート用にユーザー名とドメインを別々に抽出したい場合だ。
import re
email = "[email protected]"
# グループ1: ユーザー名, グループ2: ドメイン
pattern = r"(\w+)@(\w+\.\w+)"
match = re.search(pattern, email)
if match:
print(f"User: {match.group(1)}")
print(f"Domain: {match.group(2)}")
このテクニックは、ウェブスクレイピングにおいて非常に役立つ。手動で split() を繰り返すよりも、Pythonコードをはるかにスッキリさせることができる。
実戦経験: 「スーパーマン」になろうとしないこと
私はかつて、この世のあらゆるメールアドレスを検証できる「万能な」Regexを1行で書こうとして失敗したことがある。その結果、1週間後に見返したとき、自分でも何を書いたのか理解できなかった。
以下の3つの黄金律を覚えておこう:
- シンプルさを優先する: Regexが複雑すぎる場合は、分割するか、Pythonの
if/else文と組み合わせよう。 - 常にRaw文字列を使う: バックスラッシュによる思わぬエラーを避けるため、パターンの前には常に
rを付けること(例:r'\d+')。 - ツールを活用する: 当て推量で書かないこと。素早くテストしたいときは、Toolcraft.appのRegex Tester をよく使っている。一致結果が即座に表示されるので、デバッグ時間を大幅に節約できる。
例:ベトナムの電話番号をフィルタリングする
例えば、09 または 03 で始まる、ちょうど10桁の電話番号リストを素早くフィルタリングしたいとする:
phones = ["0912345678", "0388889999", "1234", "091-234-567"]
pattern = r"^(09|03)\d{8}$"
valid = [p for p in phones if re.match(pattern, p)]
print(f"有効な番号: {valid}")
Regexは決して難しくない。最初の15分間、少し見慣れないだけだ。ファイル名の変更やエラーログの抽出など、小さなことから使い始めてみよう。作業スピードが劇的に向上することに驚くはずだ。

