JOURNAL

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

正規表現ラボを作ってる最中、何度も「あれ、これPHPで動いたのになんでJSだと動かないんだ」を経験しました。正規表現って言語問わず同じもの、というイメージを持ってる人もいると思うんですが(自分も昔はそうでした)、実際には結構がっつり方言があります。

後読みで本番を壊した話

たとえば肯定先読み(?=...)とか否定先読み(?!...)あたりは大体どの言語でも使えるんですが、長さの決まってない後読みになると途端に言語・エンジンごとの対応がバラバラになります。JavaScriptは比較的最近になって後読みに対応した経緯があって、「古い環境だと動かない」みたいな地味な罠が実務でちょくちょく発生します。

自分も1回、これで本番エラーを出してしまい、深夜に平謝りしながら直した苦い記憶があります。

PHPのpreg_matchまわりはPCREというエンジンを使っていて、JavaScriptの正規表現エンジンとはデリミタの要否やUnicodeモードの指定方法なんかが微妙に違います。「微妙に」というのが厄介なところで、大体は動くんだけど、たまにコーナーケースだけ挙動が変わる。

JavaScriptPHP(PCRE)
デリミタ不要(/pattern/で表現)必須(/pattern/のように囲む)
Unicodeモードuフラグu修飾子
可変長後読み比較的最近対応早くから対応

この「大体動く」が一番怖いんですよね。全部動かないなら気づけるんですが。

バックエンドとフロントエンドの両方でバリデーションを書くような場面だと、この方言の違いを忘れてると「サーバー側は弾いたのにクライアント側は素通りした」みたいな不整合がふつうに起こります。正規表現ラボにJS・PCRE両方をその場で試せる機能を入れたのも、この「動いたから正しいとは限らない」を身をもって知ってほしかったからです。自分がやらかした分、余計に力が入りました。