/ 最近 .rdf 追記 編集 設定 本棚

log[20080221] JavaScript空文字列にまつわる微妙な点 (String.split(), RegExp.lastIndex)



20080221() エクスプローラはバカだエクスプローラはバカだエクスプローラはバカだdesktop.iniは目障りな上に役に立っていない(C:\Windowsが音楽フォルダって何? 実体のないフォルダ(マイコンピータごみ箱デスップーザ)の表示設定も保存し)

[javascript] JavaScript空文字列にまつわる微妙な点 (String.split(), RegExp.lastIndex)

 空文字列を split()

split()の第一パラメータ separatorが空文字列にマッチするかどうかで結果が異なる

"".split(" ").length;      // 1 (空文字列にマッチしないから)
"".split("").length;       // 0 (空文字列にマッチするので)
"".split(/\s+/).length;    // 1 (空文字列にマッチしないから)
"".split(/^$|\s+/).length; // 0 (空文字列にマッチするので)

function getClasses(element) {
  return element.className.split(/^$|\s+/);
}
 追記@2008-05-28: 空白で始まったり空白で終わるときのことを考えていなかった

上の functionでは classNameが空っぽの時には空文字列の要素を作らないが頭や尻尾に空白が付いていると空文字列の要素が残る (IEを除いて)事前トリミングする手間をかけるくらいなら一個二個の空文字列を気にせず(だけど連続する空文字列の要素は気にして) className.split(/\s+/) とする方が好みだな

 空文字列にマッチした後の lastIndex

IE7Firefox2で異なるFirefox2の方が正しいが無限ループに陥りやすい

var re = /\b/g; // 単語境界にマッチする、幅0のメタ文字。
var str = "012 456 89A";
re.lastIndex = 0;
for(var i = 0; i !== 5; ++i) {
  alert("("+ re.exec(str).index +","+ re.lastIndex +")");
  // IE7: (0,1) (3,4) (4,5) (7,8) (8,9) ...
  // Fx2: (0,0) (0,0) (0,0) (0,0) (0,0) ...
}

空文字列にマッチしていれば(IE7でスキップされるマッチがでてく) exec()の前後で lastIndexの値が変わっていなければ(Fx2でのマッチ回数が IE7より増え) indexlastIndexが同じならば lastIndex1インクリメとしておくとどちらでも間違いが起こらない

var re = /\b/g;
var str = "012 456 89A";
re.lastIndex = 0;
for(var i = 0; i !== 5; ++i) {
  var index = re.exec(str).index;
  alert("("+ index +","+ re.lastIndex +")");
  // IE7: (0,1) (3,4) (4,5) (7,8) (8,9) ...
  // Fx2: (0,0) (3,3) (4,4) (7,7) (8,8) ...
  if(index === re.lastIndex) {
    ++re.lastIndex;
  }
}

ープで

  if(index === re.lastIndex) {
    ++re.lastIndex;
  }

なんて分岐を増やすより文字列末尾にマッチする /$/ を例外として*正規表現から空文字列にマッチする可能性を排除する方が良さそう

* /$/.exec("str") の後の lastIndexプロパIE7Fx2とも最後の文字の次を指す。