2009年5月6日水曜日

IEの正規表現 string.replaceメソッドとRegExp.$n

このGW中、構想2日、作成に2日もかけて、JavaScriptでうごくテンプレートエンジンのようなものをつくった。

「エンジン」というほど大したものではなく、ようするに文字列中で変数を使用したり、if文とeach文を使えるようにしたもの。とりあえず、構造は単純──これ以上複雑なものはぼくの頭では無理──なのでFirefoxやOpera、Safariでは動く。しかしIEでは動かない。なんだか、どうしようもなくバグっている。正規表現関連の処理で躓いている?

Googleで検索してみても、正規表現についてのIEの対応状況やバグの情報が見つからない… DOMに関するものについては、本も出ているし、jQueryなどのライブラリでは当然その種の対応状況差やバグに対応してくれている。しかし、正規表現についてそういうライブラリはなさそう… こまったなぁ…

【追記】

原因が分かった。

すくなくともIE7では、Stringオブジェクトのreplaceメソッドを、第1引数に正規表現、第2引数に動的な文字列の置き換えを行うための関数を指定して呼び出したとき、この第2引数の関数内で、RegExp.$n(nは整数)を呼び出しても、ただしく動作しない。

いや、そもそもreplaceメソッドの第2引数に指定した関数のスコープ内でも、RegExp.$nがちゃんと使えるなどと確約するような文章を読んだことがあるわけでもないので、「ただしくない」などというのはちょっとアレなのだが、しかし「直前の正規表現マッチングにおける、n番目の (...) に対応する文字列を返します。」(とほほのWWW入門)というところから自然に類推すれば、使えて当然というものである。

現にFirefox3、Opera9、Safari3では使えた。そしてIE7では使えなかった(せめてundefinedなどを返してくれればまだ解決は早かったのではと思う。IE7ではRegExp.$nは──いつもではないのだが──空文字列を返してよこすという、かなり奇妙な動作をしている。第1引数として渡した正規表現ではとてもキャッチできないような文字列を返すこともあった。何にしても最悪である)。

ヒントはここ(「JavascriptのString.replaceに無名関数を渡して複雑な置換」/Electronic Genome)にあった。

string.replace(regexp, function)

という形で、replaceメソッドを呼び出したとき、第2引数の関数には、引数が渡される。この引数は正規表現による直前のマッチングの結果により数が変化するので、関数内ではarguments[n]という形でアクセスするのが都合良い。このargumentsの内容は、それはそれでおもしろいのだが(ホントに)、この件には関係ないので、そこは上記の記事を参照のこと。

しかしともかく、このarguments[n]形式でのマッチング結果へのアクセスはうまくいった。IE6、IE7でもちゃんと動作する。他の上述のブラウザでも問題なく動く。

RegExp.$n形式のときの、「n」と、arguments[n]形式でのアクセスのときの「n」とは同一でよい。ただargumentsの最後尾と最後尾の1つ前、つまり2つの引数については別。この点は上記記事を参照するべし。

0 件のコメント: