2011年3月13日日曜日

Rhinoのフィルタ演算は正規表現じゃなくても良かった

特定の属性を持った要素を取り出すコードを検索すると次のように正規表現を使ったものが多く見つかります。

// test3.js 例1
var x = <root>
    <link ref="#ref0">section 0</link>
    <link ref="http://dummy.jp/dummy.html#ref1">Outer section 1</link>
    <link ref="#ref2">section 2</link>
</root>;

var elems = x.link.(@ref.match(/^#.*/) );
for(var i in elems)
{
    var elem = elems[i]
    print('link to "' + elem + '" ... ' + elem.@ref);
}

結果は、

D:\~\rhino1_7R2>java -jar js.jar -w -strict -encoding utf-8 test3.js
link to "section 0" ... #ref0
link to "section 2" ... #ref2

これ、正規表現じゃなくても普通の文字列比較関数でもいいみたいです。 例えばこんなコードでも同じ結果になります。

// test3.js 例2
var x = <root>~略~</root>;

var elems = x.link.(@ref.substring(0, 4) == '#ref');
//var elems = x.link.(@ref.charAt(0) == '#');
for(var i in elems)
{
    var elem = elems[i]
    print('link to "' + elem + '" ... ' + elem.@ref);
}

なんか、正規表現って処理が重いイメージがあるじゃないですか。 貧乏性なので「こうすればちょっとでも速くなるんじゃないかなぁ」と思ってしまいます。 c言語とかなら普通に「(重)正規表現 > (軽)文字列比較」ですけど、javascriptだとどうなるのかな? 内部のゴニョゴニョのせいであまり変わらなかったりして?

ちなみに、文字列比較関数どころかこんなコードまで通ります。

// test3.js 例3
var x = <root>~略~</root>;

var elems = x.link.(func(@ref) );
for(var i in elems)
{
    var elem = elems[i]
    print('link to "' + elem + '" ... ' + elem.@ref);
}

function func(elem)
{
    print(elem.nodeKind() + ' : ' + elem.localName() + '="' + elem + '"');
    return elem.charAt(0) == '#';
}

結果は、

D:\~\rhino1_7R2<java -jar js.jar -w -strict -encoding utf-8 test3.js
attribute : ref="#ref0"
attribute : ref="http://dummy.jp/dummy.html#ref1"
attribute : ref="#ref2"
link to "section 0" ... #ref0
link to "section 2" ... #ref2

仕様を見たところ、このコードは間違ったコードではなさそうです。

でも間違ってないとは断言できないんだよなぁ。 仕様書は誤解が無いように過不足ない言葉遣いで淡々と書いてあるものですが、そのせいでかえって意味が分かりにくくなってることってありますよね?

このコードのフィルタ演算でやってることは、

  1. 演算結果用の空のXMLListオブジェクトを作成。
  2. x.linkの全項目をリストアップ。
  3. リストアップされた全項目についてフィルタ演算のカッコ()の中身を評価。
  4. カッコの中身の評価がtrueなら演算結果用XMLListに追加。

こういうことらしいんですけど、カッコの中身の評価が実行時にどう展開されているのかがわかりません。 例3みたいな書き方は後々まで大丈夫な仕様どおりのコードなんでしょうか? それともバッドノウハウなんでしょうか?

どちらにしても、コードは多少長くなっても分かりやすく書いた方がいいので、例3みたいな書き方はダメなんですけどね。