練炭ブログ

萌え壁紙、Irvine、DMonkey、Proxomitron などの情報を扱ってます。

DMonkey: String/RegExp.replace で0回のマッチをキャプチャすると number 0 になる

コメントなし»

[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

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です