2011年3月26日土曜日

javascriptの正規表現 globalマッチしたもの全部に処理

Rhino用だとこんなコードになるらしい。

// 角括弧[]の中身を取り出す(数字があった場合)
var text = 'a[0]bc[1]de[]fg[2][3]hij[4]klmn[';
var r = new RegExp(/\[(\d+)\]/g);
var m;

while( (m = r.exec(text) ) != null)
{
    print('m[1] = ' + m[1] );
}

結果は、

m[1] = 0
m[1] = 1
m[1] = 2
m[1] = 3
m[1] = 4

globalマッチのときは '文字列'.match(/正規表現/g) をするとマッチした部分全体の文字列が入った配列が帰ります。 カッコ内の取り出しはできないっぽい?

var text = 'a[0]bc[1]de[]fg[2][3]hij[4]klmn[';
var r = new RegExp(/\[(\d+)\]/g);
var m = text.match(r);
print(m);
print('m instanceof Array = ' + (m instanceof Array) );
print('typeof(m[0] ) = ' + typeof(m[0] ) );

結果は、

[0],[1],[2],[3],[4]
m instanceof Array = true
typeof(m[0] ) = string

つまり、カッコ内を拾うときは /正規表現/g.exec('文字列') じゃないとダメで、マッチした部分全体が欲しいときは '文字列'.match(/正規表現/g) の方が楽。

何度も正規表現を使う場合、RegExpはコードに直書きせずに毎回newした方がいいようです。 コードに直書きするとRegExpがグローバル変数として作られ、前回のexecを引きずるためです。

参考サイトは、

自分で試したコードは、

var text = 'a[0]bc[1]de[]fg[2][3]hij[4]klmn[';
var m;

print('RegExp直書き');
function test0()
{
    print('call test0()');
    
    while( (m = /\[(\d+)\]/g.exec(text) ) != null)
    {
        print('m[1] = ' + m[1] );
        if(2 < m[1])
        {
            break;
        }
    }
}

test0();
test0();
test0();

print('---------------------');
print('RegExp毎回new');

function test1()
{
    print('call test1()');
    
    var r = new RegExp(/\[(\d+)\]/g);
    while( (m = r.exec(text) ) != null)
    {
        print('m[1] = ' + m[1] );
        if(2 < m[1])
        {
            break;
        }
    }
}

test1();
test1();
test1();

実行結果、

RegExp直書き
call test0()
m[1] = 0
m[1] = 1
m[1] = 2
m[1] = 3
call test0()
m[1] = 4
call test0()
---------------------
RegExp毎回new
call test1()
m[1] = 0
m[1] = 1
m[1] = 2
m[1] = 3
call test1()
m[1] = 0
m[1] = 1
m[1] = 2
m[1] = 3
call test1()
m[1] = 0
m[1] = 1
m[1] = 2
m[1] = 3

ちなみに、「JavaScriptの正規表現リテラルが状態を持つデモ」のブラウザごとの結果は少し古い情報です。 今のブラウザで試すと全部同じ結果(下の例)になりました。 標準化されたからですかね? 試したブラウザは、

  • firefox 4.0
  • google chrome 10.0
  • Opera 11.01
  • Internet Explorer 8.0