JOURNAL

正規表現に『方言』があるという話 — JS・PHP・Pythonでの違い

「正規表現なんて、どのプログラミング言語でも同じ記号を使ってるんだから共通でしょ?」

プログラミングを始めたばかりの頃、私は本気でそう信じ切っていました。しかし、赤猫座の道具(正規表現ラボ)を作ったり、フロントとバックエンドを行き来してコードを書く中で、「正規表現には恐ろしいほど根深い『方言(Flavors)』が存在する」という現実を身をもって知ることになります。

「PHPでテストして動いた正規表現をそのままJavaScriptにコピペしたら動かない」「Safariだけ画面が真っ白になってクラッシュした」など、開発者が一度は踏み抜く正規表現の地雷と主要エンジンの違いについてまとめます。

1. 実録:Safariを巻き込んで本番クラッシュした「後読み」事件

正規表現の代表的な方言トラップが、特定パターンの後ろを検索する「後読み(Lookbehind / (?<=...))」です。

// 「円」の直前にある数字だけを抽出したい
const regex = /(?<=¥)\d+/; // 肯定後読み

この記述、PCRE(PHP)やPython、そしてChrome(V8)では何の問題もなく動きます。しかし、iOS Safariが後読みに正式対応したのはiOS 16.4(2023年春)という比較的最近のことでした。

それ以前のSafari環境でこの正規表現を実行すると、単にマッチしないだけでなく「正規表現の構文エラー(SyntaxError)」としてJavaScriptの実行がその場で即死し、ページ全体が真っ白になるという大事故を引き起こしました。深夜に冷や汗を流しながら平謝りで緊急リリースした苦い記憶は今でも忘れられません……😿

2. 言語ごとにここまで違う! 3大方言トラップ

① 可変長の後読み(長さを特定できないパターン)

「後読みの中に + や * を使いたい(例: (?<=https?://))」という場面。PCREでは比較的柔軟に動きますが、JavaScriptやPythonの標準reモジュールでは「後読みの長さが固定でない」という理由でエラー(Lookbehind requires fixed-width pattern)になります。

② 名前付きキャプチャグループの記法揺れ

マッチしたグループに名前をつける機能も、言語の歴史によって書き方が分かれています。

  • JavaScript / PCRE / C#:(?<year>\d{4})
  • Python(古くからの記法):(?P<year>\d{4})(※Pが付く)

③ Go言語(RE2)の「あえて機能を捨てた」鉄壁の思想

Go言語に標準搭載されている正規表現エンジン(RE2)は、非常に独特です。
なんと、「先読み・後読み・後方参照(\1)」が一切使えません。

欠陥品なのかと思いきや、実はこれには明確な理由があります。複雑なバックトラック(探索のやり直し)を許すと、悪意ある文字列を食わされたときにサーバーのCPUが100%に張り付いてサーバーが落ちる「ReDoS(正規表現DoS攻撃)」が発生します。RE2は安全性を最優先し、「どんなに入力文字列が長くても、必ず線形時間(O(n))で処理を終わらせる」ために高度な先読み・後読み機能を意図的に削ぎ落としているのです。

3. Unicodeプロパティ(日本語・絵文字)の扱い

ひらがなや漢字、絵文字を判定したい場合、モダンなエンジンであればUnicodeプロパティエスケープ(\p{Script=Hiragana}など)が使えます。

// JavaScriptでひらがなだけにマッチさせる(uまたはvフラグが必須)
const hiraganaRegex = /^\p{Script=Hiragana}+$/u;

ただし、これもエンジンによって u フラグが必要だったり、v フラグ(集合演算)が必要だったり、PHPでは /u 修飾子を付けないとマルチバイト文字列がバイト単位で破壊されたりと、お作法が微妙に異なります。

機能・仕様JavaScript (ES2024)PHP (PCRE2)Python (re)Go (RE2)
先読み(Lookahead)◎◎◎×(ReDoS防止のため非対応)
固定長の後読み◎(※旧Safari注意)◎◎×
可変長の後読み×△(一部制限あり)××
名前付きグループ(?<name>...)(?<name>...)(?P<name>...)(?P<name>...)
ReDoS(指数爆発)耐性△(設計注意)△(設計注意)△(設計注意)◎(絶対に爆発しない)

結論:「動いた」ではなく「どの環境で動かすか」

「この正規表現、ネットのジェネレーターで動いたからコピペしよう!」

そのジェネレーターが動いている環境(JavaScriptなのかPCREなのかPythonなのか)と、あなたがデプロイしようとしている本番環境が一致していなければ、思わぬバグやサーバー停止の引き金になります。

赤猫座の「正規表現ラボ」に、構文解析やリアルタイム検証機能を詰め込んだのも、まさにこの「言語ごとの方言と安全性の違い」を気軽に試して納得してほしかったからです。コピペで済ませず、エンジンの癖を愛せるようになると、正規表現はもっと楽しく頼もしい味方になってくれます。