Safariで後読み正規表現が使いたい時の諦め方
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だけ非対応であることがわかります。
※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株式会社 として生まれ変わりました!
「動画の地平をひらき、世の中をポジティブに。」というミッションはそのままに、VideoTouchというプロダクトに一点集中していきます。
エンジニア採用も行っています。
気になる方は弊社CTOのMeetyもどうぞ。
Discussion