禁則事項化ブックマークレット

Posted in javascript by o-taki on the 2009/7/14

ページ内の文章の色々な場所を「禁則事項」に変化させ、朝比奈さんみたいなページにする毒にも薬にもならないブックマークレット。
形態素解析とかしなくても、漢字とアルファベットとカタカナの後に特定のひらがながある場合に置換するようにするだけで意外にうまくいくということが分かった。

script 禁則事項 (ブックマークして使う)

元ネタ

参考情報

/**
 * 禁則事項ブックマークレット
 * reference -> http://zenith.sakura.ne.jp/blog/2007/04/post-48.html
 *
 * 使用方法は、変換を適用させたいページをブラウザに表示させてから
 * アドレス欄に
 * javascript:(function(){var u="http://ブックマークレット設置箇所";var d=document;var s=d.createElement('script');s.charset="UTF-8";s.src=u;d.body.appendChild(s);})()
 * と入力します。
 */

// 名前空間用のオブジェクト window.Negisio が存在しなければ定義
if (!("Negisio" in window))
{
  Negisio = {};
}

// 名前空間用のオブジェクト window.Negisio.Bookmarklet が存在しなければ定義
if (!("Bookmarklet" in window.Negisio))
{
  Negisio.Bookmarklet = {};
}

/**
 * HTML 文章を禁則事項するブックマークレットの新しいインスタンスを初期化します。
 */
window.Negisio.Bookmarklet.Arisyu = function ()
{
  this.filters = [];
}

/**
 * 指定した要素に変換フィルタを適用します。
 *
 * @param HTMLElement element 対象の要素。
 * @param bool recursive 子要素にも再帰的に適用するなら TRUE、しないなら FALSE。
 */
window.Negisio.Bookmarklet.Arisyu.prototype.filter = function (element, recursive)
{
  for (var i = 0, iLast = this.filters.length; i < iLast; i++)
  {
    var f = this.filters[i];

    f.apply(element);

    if (recursive)
    {
      for (var j = 0, jLast = element.childNodes.length; j < jLast; j++)
      {
        var child = element.childNodes[j];
        this.filter(child, recursive);
      }
    }
  }
}

/**
 * 指定した要素が持つ全ての子要素のうち、変換対象の要素のテキストを禁則事項します。
 * 子要素は再帰的に列挙されます。
 *
 * @param HTMLElement element 対象の要素。
 */
window.Negisio.Bookmarklet.Arisyu.prototype.apply = function (container)
{
  this.filter(container, true);
}

/**
 * 正規表現により文章を置換するフィルタの新しいインスタンスを初期化します。
 */
window.Negisio.Bookmarklet.Arisyu.RegExpFilter = function ()
{
  /**
   * 置換候補の正規表現と結果の辞書
   */
  this.dictionaries = [
      {
        "pattern": "([一-龠々〆ヵヶ]|[ァ-ヴー]|[a-zA-Z0-9 _\-])+(を|で|が|の|的|と|する|して|した|しよう|は|や])",
        "option": "gm",
        "replace": "禁則事項$2"
      }
    ];

  /**
   * 正規表現オブジェクトのキャッシュ
   */
  this.regexpCache = [];
}

/**
 * 指定された要素がフィルタの適用対象かどうかを取得します。
 *
 * @param HTMLElement 調べる対象の要素。
 * @return bool 適用対象なら TRUE、対象外なら FALSE。
 */
window.Negisio.Bookmarklet.Arisyu.RegExpFilter.prototype.isAcceptElement = function (element)
{
  var isAccept;

  switch (element.nodeName.toLowerCase())
  {
    case 'style':
    case 'script':
    case 'frame':
    case 'code':
      isAccept = false;
      break;

    default:
      isAccept = true;
  }

  return isAccept;
}

/**
 * 指定された要素へフィルタを適用します。
 *
 * @param HTMLElement 適用対象の要素。
 */
window.Negisio.Bookmarklet.Arisyu.RegExpFilter.prototype.apply = function (element)
{
  if ("parentNode" in element && element.parentNode != null)
  {
    if (!this.isAcceptElement(element.parentNode))
    {
      return;
    }
  }

  if (element.nodeName.toLowerCase() != "#text")
  {
    return;
  }

  var nodeValue = element.nodeValue;

  for (var i = 0, iLast = this.dictionaries.length; i < iLast; i++)
  {
    var dictionary =  this.dictionaries[i];

    if (!(i in this.regexpCache))
    {
      this.regexpCache[i] = new RegExp(dictionary.pattern, dictionary.option);
    }

    var regexp = this.regexpCache[i];
    nodeValue = nodeValue.replace(regexp, dictionary.replace);
  }

  element.nodeValue = nodeValue;
}

////////////////////////////////////////////////////////////////////////////
// ここから実行
////////////////////////////////////////////////////////////////////////////

var arisyu = new Negisio.Bookmarklet.Arisyu();

// フィルタ設定
arisyu.filters = [
    new Negisio.Bookmarklet.Arisyu.RegExpFilter()
  ];

// トップ レベルの文章に適用
arisyu.apply(window.document);

// フレームがあればそちらも適用
if ("frames" in window)
{
  for (var i = 0, iLast = window.frames.length; i < iLast; i++)
  {
    arisyu.apply(window.frames[i].document);
  }
}

Comment

Trackback URL