🦖

Safariで後読み正規表現が使いたい時の諦め方

2022/08/05に公開

TLDR

  • Safariでは正規表現の後読みが使えず、シンタックスエラーになってしまう。
  • 諦めて後読みを使わない書き方にする。
  • /(?<=foo)bar/ なら /(?:foo)(bar)/ にして、「bar」の部分はキャプチャグループとして取得する。

例えば「foo」の次に「bar」がくる場合にだけマッチさせたい場合、JSでは /(?<=foo)bar/ という正規表現を使えます。

"bar".match(/(?<=foo)bar/) // null
"foobar".match(/(?<=foo)bar/) // ['bar', index: 3, input: 'foobar']

Safariは後読みが非対応

よしよしこれでいいな、と思ったら実はSafariでは後読みをサポートしていません。
後読みの構文をサポートしていないため、シンタックスエラーになります。

SyntaxError: Invalid regular expression: invalid group specifier name

「invalid group specifier name」と出ているので、後読みシンタックスを知らないので名前付きグループとして解釈しようとしてエラーになっているんじゃないでしょうか。

caniuse.com を見ると、Safariだけ非対応であることがわかります。

https://caniuse.com/js-regexp-lookbehind
caniuse.comの後読み正規表現のサポート表。Safariでは後読みの対応が未定
※2022/08/05時点のスクリーンショット

後読みを使わずに「前に〇〇がある時」というマッチをする

諦めて後読みを使わない方法を取りましょう。
/(?:foo)(bar)/ のように、後読みではなく非キャプチャグループを使って「foo」があることをチェックしましょう。
そして、実際のユースケースでは「bar」の部分は何かしらのパターンだと思うので、「foo」を除いたマッチ結果を取り出したいでしょう。「bar」の部分をキャプチャグループにしておけばいいです。

const match = "foobar".match(/(?:foo)(bar)/); // ['foobar', 'bar', index: 0, input: 'foobar']
match[1]; // 'bar'

マッチした位置も欲しい

マッチした「bar」が文字列の中でどの位置にいるのかも知りたい場合があります。
後読みを使える場合ならマッチした結果オブジェクトの index を参照すればいいだけですが、後読みを諦めた方法では index は「foo」を含んだマッチ位置となってしまいます。
これを解決するには「foo」の長さを考慮してあげればいいです。

const match = "ほげfoobar".match(/(foo)(bar)/);
match.index; // 2 ← 先頭からのfoobarの位置であってbarの位置ではない。
const [, lookbehind, captured] = [...match];
const index = match.index + lookbehind.length; // 5 ← 先頭からのbarの位置。
captured; // 'bar'

宣伝

🍏が所属する株式会社Viibarは2022年8月1日に VideoTouch株式会社 として生まれ変わりました!
https://videotouch.co.jp/

「動画の地平をひらき、世の中をポジティブに。」というミッションはそのままに、VideoTouchというプロダクトに一点集中していきます。

https://videotouch.jp/

エンジニア採用も行っています。
気になる方は弊社CTOのMeetyもどうぞ。
https://meety.net/matches/qKaieudVrZSA

Discussion