hogehoge foobar Blog Style Beta

Web,Mac,Linux,JavaScript,Perl,PHP,RegExp,Git,Vim,Redmineなど技術的なことのメモや、ちょっと便利そうなものの紹介をしています。

JavaScriptのreplaceの引数としてfunctionを使用する

JavaScriptのreplaceの第2引数には関数(function)を使用することが出来ます。
その簡単な使い方と簡単な説明です。

※ずっと前にも一度書いたことがあったのですが、読み返したときに意味不明状態になるような内容だったので、情報を整理して改めて書いています。
以前のエントリ:JavaScriptのreplaceの関数オブジェクトを渡せることを知った

一般的なreplaceの使い方

一般的なreplaceの使い方は、

  • 第1引数 : 置換え前の文字列(正規表現も可)
  • 第2引数 : 置換え後の文字列(正規表現のグループは、$1,$2,…で指定)

になります。

一般的なreplaceのサンプルコード
var str = 'hoji1hoji2hoji3';
var str2 = str.replace(/(ho)ji([0-9])/g, '$1ge$2');
alert(str2); /* => hoge1hoge2hoge3 */

第2引数にfunctionを渡した場合のreplaceの使い方

第2引数としてfunctionを渡す場合のreplaceの使い方は、

  • 第1引数 : 置換え前の文字列(正規表現も可) ※通常の場合と同じ
  • 第2引数 : 無名関数 or 関数

になります。
上記の「通常のreplaceの使い方」のサンプルコードと同じ事を、第2引数にfunctionを渡して実現しようとするとこんな感じになります。
※便宜上、console.logやalertを含めています。

第2引数にfunctionを渡した場合のreplaceのサンプルコード
var str = 'hoji1hoji2hoji3';
var str2 = str.replace(/(ho)ji([0-9])/g, function(all, group1, group2){
                console.log(arguments);
                alert(all);     /* => hoji1, hoji2, hoji3 */
                alert(group1);  /* => ho,    ho,    ho    */
                alert(group2);  /* => 1,     2,     3     */
                return group1 + 'ge' + group2;
            });
alert(str2); /* => hoge1hoge2hoge3 */

ここで重要なのが、第2引数として渡したfunctionの引数に何がわたってくるか?です。

第2引数のfunctionのargumentsの中身

上記のサンプルコードの第2引数のfunctionのargumentsを「console.log」等で出力してみると、こんな感じに表示されます。
※「console.log」ってPHPの「var_dump」みたいで便利です!

FireBugで確認(抜粋)
["hoji1", "ho", "1", 0, "hoji1hoji2hoji3"]
["hoji2", "ho", "2", 5, "hoji1hoji2hoji3"]
["hoji3", "ho", "3", 10, "hoji1hoji2hoji3"]
GoogleChromeで確認(抜粋)
Object
0: "hoji1"
1: "ho"
2: "1"
3: 0
4: "hoji1hoji2hoji3"

Object
0: "hoji2"
1: "ho"
2: "2"
3: 5
4: "hoji1hoji2hoji3"

Object
0: "hoji3"
1: "ho"
2: "3"
3: 10
4: "hoji1hoji2hoji3"
第2引数にfunctionのargumentsの説明(Webtech Walkerより)

argumentsの中身の説明については、Webtech Walkerさんのページに詳しい説明がありますので、引用させていただきます。

arguments[0] => マッチした文字列全体
arguments[1] ~ arguments[arguments.length - 3] => ()でグルーピングした文字列が順番に
arguments[arguments.length - 2] => マッチした文字が先頭から何文字目か
arguments[arguments.length - 1] => 検索対象の全体の文字列
http://webtech-walker.com/archive/2010/02/15094126.html

少し応用してみる

基本的な使い方が分かったので少し応用してみます。
文字列(%s)にしか対応していないsprintfっぽい関数を作ってみました。

sprintfっぽい関数(arguments版)

この関数の使い方はこんな感じです。

  • 第1引数 : フォーマット用文字列(%sのみ対応)
  • 第2引数以降 : %sに埋め込む文字列

JavaScriptの関数の引数は「arguments」で配列として参照することができるので、第2引数以降の受け取りにはこれを利用しています。
この関数の場合、第1引数はフォーマット用文字列なので、第2引数以降については「arguments」の2番目以降、つまり「arguments[1]」から参照するようにしています。

var sprintf = function(format){
    var ary = arguments;
    var idx = 1;
    return format.replace(/%s/g, function(all, group){
        return ary[idx++];
    });
}
var str = sprintf('%s年%s月%s日', '2010','9','16' );
alert(str);  /* => 2010年9月16日 */
sprintfっぽい関数(ハッシュ版)

上記の関数の改良版です。この関数の使い方は、

  • 第1引数 : フォーマット用文字列(%name%で指定)
  • 第2引数 : フォーマットに埋め込む文字列(ハッシュ配列)

上記のarguments版だと、第2引数以降の順番を気にする必要があったので、フォーマット用文字列に「%ハッシュのキー%」という形で、順番に関係なく指定されたキーの値がフォーマットに埋め込まれるようにしてみました。

var sprintf = function(format, hash){
    return format.replace(/%([a-z][a-z0-9]+)%/g, function(all, group){
        return hash[group];
    });
}
var str = sprintf('%year%年%month%月%day%日', { 'year':'2010', 'month':'9','day':'16' } );
alert(str);  /* => 2010年9月16日 */

やっぱりJavaScriptっておもしろいですわ。

今回参考にしたページ

javascriptのreplaceにfunctionを渡す - Webtech Walker
http://webtech-walker.com/archive/2010/02/15094126.html

#2 プログラマーの三大美徳その2「短気」- 404 Title Not Found:ITpro
http://itpro.nikkeibp.co.jp/article/Watcher/20061005/250058/?ST=oss