[4月29日追記] 訂正: number 0 になるのではなく、キャプチャ結果が引数として渡されないため、マッチした位置(index)を参照していただけでした(0回のマッチと1回以上のマッチの場合で arguments.length が違う)。申し訳ありません。
- String.replace() や RegExp.replace で、
- 正規表現に
(~)?
や(~)*
を使い、 - 置換文字列として関数を指定していると、
- 最後のキャプチャ部分が0回の繰り返しにマッチした時、
キャプチャ結果として関数の引数に number 型の 0 が渡される。キャプチャ結果が関数の引数に渡されない。
通常は空文字列が渡されるのですが、上記のように最後のキャプチャが0回マッチだと 0 が渡されますキャプチャ結果が渡されません。他の文字列と + 演算子で繋げたりすると '0' という文字列として扱われてしまうので注意が必要です。
alert (
'ab'.replace (/a(\d)?b/, function (s, p1) { return typeof p1; })
);
//number
alert (
'ab'.replace (/a(\d)*b/, function (s, p1) { return typeof p1; })
);
//number
なお、各種ブラウザでは0回マッチでもキャプチャ結果が引数として渡されますが、その内容は Firefox 12 では空文字列(string)、Internet Explorer 8 と Google Chrome 18 では undefined になります。
常に文字列で渡される Firefox 形式が楽だと思うのですが、ECMAScript 的にはどの動作が正しいんでしょうか?
対処法
- 正規表現の末尾に
()
を付ける。 (~)?
を((~)?)
のように外側をキャプチャする。置換文字列として指定された関数内で、number 型か調べて空文字列に置き換える。
一つ目の方法の例。
alert(
'ab'.replace(/a(\d)?b()/, function (s, p1) { return typeof p1; })
);
//string
alert(
'ab'.replace(/a(\d)*b()/, function (s, p1) { return typeof p1; })
);
//string