JavaScript重箱の隅  新JavaScript入門  JavaScript,Neo-Generation  掲示板  表紙
10. 文字列(2)  12. 文字列(4) 
JavaScript 重箱の隅
Written 5/17/02
文字列(3)
このページでは正規表現について調べていきます。 正規表現は遅いという印象がありますが、果たしてどうでしょう。
まず、非常に簡単に、文字列の中に"9"という文字があるか調べましょう。
    //ループ1
    var start_t = new Date();
    var s = "0123456789";
    var b;
    for(var j = 200000; j; j--)
        b = (s.indexOf("9") != -1);
    return (new Date() - start_t) / 1000;
    
    //ループ2
    var start_t = new Date();
    var s = "0123456789";
    var b;
    for(var j = 200000; j; j--)
        b = /9/.test(s);
    return (new Date() - start_t) / 1000;
    
    scripts/bench057a.js
    scripts/bench057b.js
    t0 : -54.25054388807067
    ループ1 : 0.42
    ループ2 : 1.46
    ループ1 - ループ2 : -1.08 - -1
 
正規表現を使ったほうがずいぶん時間がかかるんですね。
次のようにあらかじめ Regular Expression オブジェクトを定義しておくとどうでしょう。
    //ループ3
    var start_t = new Date();
    var s = "0123456789";
    var reg = /9/;
    var b;
    for(var j = 2000000; j; j--)
        b = reg.test(s);
    return (new Date() - start_t) / 1000;
    
    scripts/bench058a.js
    scripts/bench058b.js
    t0 : -3.8873677349816597
    ループ1 : 0.43
    ループ3 : 0.47
    ループ1 - ループ3 : -0.06 - -0.02
 
これだとかなり差が詰まっています。 ちなみに compile メソッドを使っても結果は変わりませんでした。
もうちょっと普通の正規表現の使い方をしてみましょう。 文字列に数字が含まれているかを調べます。
    //ループ4 JScript5以上
    var start_t = new Date();
    var s = "0123456789";
    var b;
    for(var j = 200000; j; j--) {
        var len = s.length;
        var code;
        for(var k = 0; k < len; k++) {
            code = s.charCodeAt(k);
            if(b = (48 <= code && code <= 57))
                break;
        }
    }
    return (new Date() - start_t) / 1000;
    
    //ループ5
    var start_t = new Date();
    var s = "0123456789";
    var reg = /\d/;
    var b;
    for(var j = 200000; j; j--)
        b = reg.test(s);
    return (new Date() - start_t) / 1000;
    
    scripts/bench059a.js
    scripts/bench059b.js
    t0 : 7.831073410077608
    ループ4 : 0.58
    ループ5 : 0.47
    ループ4 - ループ5 : 0.08 - 0.13
 
正規表現を使わないほうも工夫はしましたが、 さすがに正規表現を使ったほうが速いです。
上は最初に数字が見つかったのでまだ差が小さいですが、 後ろのほうまで見つからないと悲惨なことになっています。
    //ループ6
    var start_t = new Date();
    var s = "abcdefghi9";
    var b;
    for(var j = 200000; j; j--) {
        var len = s.length;
        var code;
        for(var k = 0; k < len; k++) {
            code = s.charCodeAt(k);
            if(b = (48 <= code && code <= 57))
                break;
        }
    }
    return (new Date() - start_t) / 1000;
    
    //ループ7
    var start_t = new Date();
    var s = "abcdefghi9";
    var reg = /\d/;
    var b;
    for(var j = 200000; j; j--)
        b = reg.test(s);
    return (new Date() - start_t) / 1000;
    
    scripts/bench060a.js
    scripts/bench060b.js
    t0 : 360.46482905877445
    ループ6 : 4.43
    ループ7 : 0.48
    ループ6 - ループ7 : 3.93 - 3.98
 
正規表現を使うとほとんど変わらないです。
結論としては、本来正規表現を使う場面では使いましょう、ということです。
上では test メソッドを使っていますが、 RegExp オブジェクトに結果を反映させるなどの処理をしなければならない exec メソッドを試してみましょう。
    //ループ8
    var start_t = new Date();
    var s = "abcdefghi9";
    var reg = /\d/;
    var b;
    for(var j = 200000; j; j--)
        b = reg.exec(s);
    return (new Date() - start_t) / 1000;
    
    scripts/bench061a.js
    scripts/bench061b.js
    t0 : -124.71018789165836
    ループ7 : 0.48
    ループ8 : 2.36
    ループ7 - ループ8 : -1.92 - -1.85
 
ずいぶん遅いんですね。 test メソッドが用意されているはずです。
indexOf の正規表現版ともいえる search メソッドも見ておきましょう。
    //ループ9
    var start_t = new Date();
    var s = "abcdefghi9";
    var reg = /\d/;
    var b;
    for(var j = 200000; j; j--)
        b = s.search(reg);
    return (new Date() - start_t) / 1000;
    
    scripts/bench062a.js
    scripts/bench062b.js
    t0 : -3.749999999999902
    ループ7 : 0.47
    ループ9 : 0.52
    ループ7 - ループ9 : -0.08 - -0.02
 
意外にもこれは使えますね。exec メソッドの遅さは配列を返しているのが原因だったのかな。
first, prev, next, exit