JavaScriptでの正規表現失敗談!lookbehindが特定のブラウザで動かなかった話

はじめに

こんにちは。アソビューでエンジニアをやっています。小池です。

正規表現、ほとんどのシステムでどこかでは使われていると思います。多くのエンジニアが1度は書いたことがあると思います。今回はその正規表現の話です。

僕は正直に言うと、正規表現ナニモワカラナイの人間です。ただ、何度かは書いたことはあって、その都度調べながらわからないなりに書いてきました。また、最近だとAIがスッと教えてくれると思います。なので今回もAIに教えてもらって書いたのですが、まったく意識の外だったエラーを踏んだのでそのことについて書きたいと思います。

今回の事象は正規表現の規格や標準などを知っていれば気付けたかもしれませんが、知らないと踏むよなーと思ったので今回共有したいと思いました。

発生した事象

簡潔に書くと、lookbehind (後読み) を利用して書いたJavaScriptでの正規表現が、特定のクライアント (具体的には iOS 16.3以下のブラウザ) では利用できなかった事象です。
Lookbehind in JS regular expressions

今回は入力項目のバリデーションを改善しようとしており、AIを活用してlookbehindを使った正規表現を実装していました。 正規表現自体の検証はテストも書いてしっかり行っており、ブラウザでの動作確認もOK!だったのですが、一部の端末でエラーとなっているという話が上がってきました。

QAチームやアプリチームに協力してもらいエラーとなる端末を絞っていくと、どうやらiOSの特定のバージョンで発生することがわかってきて、その後はDevinなどAIにも聞いてみたりして事象を特定していくと、今回実装した正規表現でJSの実行エラーが発生していました。

lookbehindとは (簡単に)

直前のパターンをマッチさせる機能で、positive lookbehind (肯定後読み) と negative lookbehind (否定後読み) が利用できます。 たとえば以下の例だと、直前の.を表現するpositive lookbehind (?<=\.) を利用して、直前に.のある数値をマッチさせています。

const result = /(?<=\.)\d+/.exec(11.22);
result[0];
=> '22'

正規表現の標準

今回の事象とはあまり関係ありませんが、正規表現の標準について軽く整理しておきます。

POSIXだと以下3種類が定義されています。

  • 単純正規表現 (SRE)
  • 基本正規表現 (BRE)
    • UNIXのコマンドなどでデフォルトで利用できる正規表現 (grepなど)
  • 拡張正規表現 (ERE)
    • -Eオプションなどで利用する正規表現 (grep -Eなど)

また、上記の拡張正規表現をさらに拡張したものがPerlの正規表現で、その他のプログラミング言語にはこのPerlの正規表現が取り込まれていることが多いです。
※言語間で完全に互換性があるわけではないようです

JavaScriptでの正規表現

では今回書いたJavaScriptでの正規表現について見ていきます。

ECMAScript

まず、JavaScriptの標準はECMAScriptです。そのため、JavaScriptの正規表現はECMAScriptに準拠します。(おそらくここが一番のポイントで、この意識があれば気づくタイミングもあったかもしれません。)

当たり前ですが、ECMAScriptには機能が追加されていきます。JavaScript、ブラウザはその仕様に沿って実装が対応されていきます。これは正規表現の機能も同じことで、正規表現も機能、文法が追加されます。そして、新しく追加された機能はそれより古いブラウザでは利用できないことが多いです。

lookbehind

今回問題となったJavaScript正規表現のlookbehind文法は、ECMAScript 2018 (ES2018) で取り込まれています。そして、iOSに取り込まれたのは iOS 16.4 (Safari 16.4) からです。

つまり、iOS 16.3以下 (Safari 16.3以下) では利用できないということになります。

もちろん、iOSだけではなくPCでの古いブラウザもlookbehindを利用できない場合はありますが、Chromeでは2017年に追加されており、追加からしばらく経っています。一方、Safari 16.4がリリースされたのは2023年で一定利用者もいるため、問題となりやすいように思います。

また、正規表現の機能は他にも追加されているので、それらを利用する場合もブラウザなどの対応状況を確認しておくと安心です。
あなたの知っている正規表現はもう古い! 正規表現の新常識(ES2018編)

他の言語では

他のプログラミング言語でもバージョンアップで正規表現の機能が追加されたりするため、言語バージョンによっては利用できない機能、文法も存在しますが、おそらくビルド時などに気付けることが多いかと思います。

JavaScriptの正規表現は実行ブラウザに依存するため、特に注意が必要です。

おわりに

今回は正規表現を使う前に知っておきたいことについて整理しました。僕は雰囲気で使っていた正規表現ですが、思わぬ落とし穴があることを学べました。
特に、JavaScriptで正規表現を扱う場合は、正規表現で扱う文法、機能がブラウザで対応されているか意識する必要があることを知りました。
僕は正規表現自体の書き方がこれであっているかどうかばかり気にしてしまっていて、今回の事象はまったく意識できていませんでした。
この手の標準や規格絡みの問題は見落としやすく、知っていないと気付けないものかと思います。
ブラウザや端末の環境を網羅的にテストするのはなかなか難しいとも思います。

このブログで頭の片隅にでも入れていただければ幸いです!

採用案内

アソビューでは、一緒に働くメンバーを大募集しています!カジュアル面談も実施しておりますので、少しでもご興味をお持ちいただけましたら、ぜひお気軽にご応募ください! www.asoview.com

参考