SimpleBoxes

[javascript]文字の実体参照化

Javascript で文字の実体参照化を行う関数が phpspot開発日誌 にて、紹介されています

引用元なんでしょうか、Tudástár - Prog.Hu というサイトにリンクが張られていましたが、当方の環境からではオリジナルのコードを見つけられませんでした。

function htmlspecialchars(ch) {
  ch = ch.replace(/&/g,"&") ;
  ch = ch.replace(/"/g,""") ;
  ch = ch.replace(/'/g,"'") ;
  ch = ch.replace(/</g,"&lt;") ;
  ch = ch.replace(/>/g,"&gt;") ;
  return ch ;
}

ここでは replace を使って正規表現による文字置換によって実装されています。

Javascript で HTMLエスケープを行うPHP関数、htmlspecialchars を実装」でも触れられている通り、文字クラスの prototype による実装も可能で、その場合には、以下のようなコードになるでしょう。

String.prototype.htmlspecialchars = function() {
  ch = this + "";
  ch = ch.replace(/&/g,"&amp;") ;
  ch = ch.replace(/"/g,"&quot;") ;
  ch = ch.replace(/'/g,"&#039;") ;
  ch = ch.replace(/</g,"&lt;") ;
  ch = ch.replace(/>/g,"&gt;") ;
  return ch ;
}

ただ、この場合、htmlspecialchars なんて名前だと長くて分かりにくい気もするので、prototype.js のように escapeHTML のような名前にしておくのが無難かもしれません。

個人的には「実体参照化」という意味を込めて「entitize」という英単語をでっち上げちゃいますが。

さて、ここで紹介したスクリプトは replace を使っていますが、使わなくても実装できます。

String.prototype.entitize = function()
{
  var str = "" + this;
  str = str.split("&").join("&amp;");
  str = str.split("<").join("&lt;");
  str = str.split(">").join("&gt;");
  str = str.split('"').join("&quot;");
  str = str.split("{").join("&#123;");
  str = str.split("}").join("&#125;");
  str = str.split("'").join("&#039;");
  return str;
}

splitjoin を使います。

perl だと正規表現を使った置換よりも組み込み関数 splitjoin を駆使した後者の方が実行速度が速そうです。

javascript だとどうなんだろう?と思って、簡単なスクリプトを組んで実験してみてみました

Firefox 2.0.0.8 と Safari 2.0.4 と Opera 9.23 (いずれも Mac OS X 版)を使ってテストしたところ、

  • Firefox : split の方が速い (2 〜 3 倍)
  • Safari / Opera : replace の方が速い (1.5 〜 3.5倍)

という結果になりました。ブラウザによって変わってくるので、どっちがいいかはこれだけでは判断できない感じでしょうか。

ちなみに実体参照化の逆変換を行うスクリプトは以下のようになります(split による実装ですが、replace による実装もほぼ同様です)。

String.prototype.detitize = function()
{
  var str = "" + this;
  str = str.split("&#039;").join("'");
  str = str.split('&#123;').join("{");
  str = str.split('&#125;').join("}");
  str = str.split("&quot;").join('"');
  str = str.split("&gt;").join(">");
  str = str.split("&lt;").join("<");
  str = str.split("&amp;").join("&");
  return str;
}

実体参照化の場合は、& の変換を一番先に行う必要があり、逆実体参照化の場合は、&amp; の変換を一番最後に行う必要があります。

ちなみに entitize , detitize は共に造語です。英語圏で通用するかは全く分かりません。

以下は、当エントリーで使ったテストコードです。

String.prototype.entitize = function()
{
  var str = "" + this;
  str = str.split("&").join("&amp;");
  str = str.split("<").join("&lt;");
  str = str.split(">").join("&gt;");
  str = str.split('"').join("&quot;");
  str = str.split("{").join("&#123;");
  str = str.split("}").join("&#125;");
  str = str.split("'").join("&#039;");
  return str;
}
String.prototype.entitize2 = function()
{
  var str = "" + this;
  str = str.replace(/&/g ,"&amp;");
  str = str.replace(/</g ,"&lt;");
  str = str.replace(/>/g ,"&gt;");
  str = str.replace(/\"/g,"&quot;");
  str = str.replace(/{/g ,"&#123;");
  str = str.replace(/}/g ,"&#125;");
  str = str.replace(/\'/g,"&#039;");
  return str;
}
Benchmark = function()
{
  this.buffer = (new Date()).getTime();
  return this;
}
Benchmark.prototype = {
  check : function()
  {
    return (new Date()).getTime() - this.buffer;
  }
};
var number = 10000;

var text2 = "& this is a ''<br class=\"check\">test</br>.";
var bench2 = new Benchmark();
for (var i=0;i<number;i++)
{
  text2.entitize2();
}
document.write('split : ' + bench2.check() + '<br />');

var text = "& this is a ''<br class=\"check\">test</br>.";
var bench = new Benchmark();
for (var i=0;i<number;i++)
{
  text.entitize();
}
document.write('replace : ' + bench.check() + '<br />');

スポンサーリンク

<< 月を撮影してみる :: オークランド動物園(Auckland Zoo)に行ってきました >>