Python | 正規表現の性能とアンチパターン(上級向け)

Python
スポンサーリンク

では、爆発的バックトラッキング(catastrophic backtracking)を起こす典型パターンと、それを 安全に書き換えた例 を一覧表にしました。Python 初心者〜中級者が理解しやすいように、短いコード例付きにします。


爆発的バックトラッキング パターン一覧と安全な書き換え例

#危険なパターン何が危険かサンプル文字列安全な書き換え例解説
1(a+)+$貪欲量指定の多重ネスト → 失敗時に組み合わせを全探索"aaaaab"a+$余計な括弧を省き、1回の貪欲量指定に変更
2`(aaa)+$`選択肢の共通部分で分岐爆発"aaaaab"a+$
3`(aaaaaa)+$`選択肢が多い場合の指数探索"aaaaab"
4(.*a)+b.* が貪欲 → バックトラック爆発"aaaaac".*?a または文字クラス限定非貪欲 *? で最小マッチにする、または文字クラスで範囲を限定
5(a+)?a{30}bオプションと量指定の組み合わせで分岐が多すぎる"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"a{31}b明確に回数を指定し、分岐を減らす
6`(abab)+c`共通接頭辞によるバックトラック"ababababx"
7(\d+)*$数字の多重ネスト"1234567x"\d+$余計なグループの重複を削除
8`(aba)*c`選択肢の共通部分 → 失敗時に組み合わせ全探索"ababababx"`(?:ab
9([a-z]+)+d小文字文字列の多重ネスト"aaaaaaaax"[a-z]+d1回の貪欲量指定で十分
10(a.*b)+c貪欲な .* + 繰り返し → 長い文字列で爆発"axxxxxxxbxxxxxxc"(a.*?b)+c.*? 非貪欲で試行回数を減らす

補足ポイント

  1. 貪欲量指定 * / + の多重ネスト は最も典型的な爆発パターン。
  2. 選択パターン OR (|) の共通接頭辞 はバックトラックを増やす原因。
  3. 解決策の共通原則
    • 余計な括弧 () を非キャプチャ (?: ) にする
    • 貪欲 * → 非貪欲 *? を使う
    • OR の共通部分は文字クラス [ ] でまとめる
    • 回数が分かる場合は {m,n} で明示
    • 可能なら正規表現を分割して処理する

Python で安全性を確認する方法

import re, time

patterns = [r"(a+)+$", r"(a|aa)+$"]
text = "a" * 30 + "b"

for pat in patterns:
    start = time.time()
    re.match(pat, text)
    end = time.time()
    print(f"{pat}: {end - start:.5f}秒")
Python
  • 危険パターンは文字数が増えると秒数が爆発的に伸びます。
  • 安全パターンに置き換えると瞬時に終わります。

💡 この表を使えば、「この書き方は危険 → 安全な書き方に置き換え」 の基本ルールがすぐに確認できます。
実務で長いテキストやログを扱う場合、まずこの表のパターンをチェックするだけで安全性がぐっと上がります。

Python
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました