正規表現でよくハマるミスがありますが、それがバグの原因になっていることに気づいた、そんな一幕がありました。
InstantClickとは
最近は「全部JavaScriptで組んでシングルページアプリケーション」というサイトも多いですが、InstantClickは、ページ遷移をJavaScriptで乗っ取る&クリック前にプレロードを始めることでページ遷移を高速化する、というライブラリです。単体で使う分には、Turbolinksより取り回しも機能性もいいかな、というイメージです。
画面も頭の中も真っ白
そして、既存のサイトにInstantClickを入れて高速化しようと、試験的に入れてみたのですが、ページ遷移した後に得られる画面が真っ白になってしまうというトラブルに見舞われました。
WebサイトのHTMLや、InstantClick自体のコードも検証していったところ、原因を見つけ出しました。
function removeNoscriptTags(html) {
/* Must be done on text, not on a node's innerHTML, otherwise strange
* things happen with implicitly closed elements (see the Noscript test).
*/
return html.replace(/<noscript[\s\S]+<\/noscript>/gi, '')
}
ありがちなミス
多くの処理系では、正規表現はデフォルトで最長一致するようになっています。"foo" and "bar"
のような例で、/".*"/
のような正規表現でヒットさせると、文字列全体にヒットしてしまいます。けっこうやらかしがちです。
1文字なら/"[^"]*"/
のように除外指定で書いてもそこまで手間ではないのですが、たとえば「</p>
が出てこないうち」というようなものは(否定先読みが使えるかもしれませんが)書くのが煩雑になります。そこで、+
や*
といった量指定子につける?
というオプションがあって、条件を満たす最短の文字列にヒットさせられるようになります。これを使えば/<p>.*?</p>/
で「<p>
要素全体」という形でヒットさせられます1。
ここでは、文書の最初の<noscript
から最後の</noscript>
まで、問答無用でヒットしてしまいます。さすがにおかしいので、Issueを立てました。もっとも、ここまでわかっているのならプルリクのほうがよかったかもしれませんが。
-
なお、多重に書けない
<p>
や<noscript>
で気にする必要はないのですが、<div>
や<span>
のような、同じタグでネストできるものを正規表現で処理しようとすると厄介です(数学的に純粋な正規表現や、JavaScriptの範囲内の正規表現では不可能です)。 ↩