すべてがカナになる:リリースすべてがカナになる:リリース

2009/05/12

最近、「ネットでモノを生み出すということ」という本を読んでいるのですが、そこで知った、日本語カナモジ化運動(財団法人 カナモジカイ 最近も更新されてる!!)という存在に触発されて、すべてがカナになる機能を作ってみました。
これはブログのタイトルや、文章、メニュー等の日本語をすべてカナにすることができます。はい、ただのネタです。実際の動作デモは以下

「すべてがカナになる」をクリックすると・・・・
すべてがカナになる

どうでしょう?驚きました?w こちらで元にもどせます。
(動作しない場合は、環境とエラー状況等をコメントしていただけると助かります。)

仕組みの概要ですが、クリックされたときにjavascriptでタグ内のhtmlをmecabに解析させて、ひらがなと漢字をすべてカナにしたもので上書きします。しりとるの少し応用編て感じです。処理フローは以下のようになります

  • javascriptでbodyタグ内のhtmlをぶっこ抜き、カナ変換用mecab apiに送信
  • htmlを受け取ったmecab api はタグ以外の部分をカナにして返信
  • 再びjavascriptで、カナになったhtmlで上書き

htmlの抜き出し

javascriptは、subetegakananinaru.js を読み込んでいます。そしてその中では、changeKANAという関数を定義しています。

<script type="text/javascript" src="/js/subetegakananinaru.js"></script>

subetegakananinaru.jsの中身は以下

 var changeKANA = function(){
  // XMLHttp通信
  var http = (function(){
   var request_type;
   var browser = navigator.appName;
   if(browser == "Microsoft Internet Explorer"){
    request_type = new ActiveXObject("Microsoft.XMLHTTP");
   }else{
    request_type = new XMLHttpRequest();
   }
    return request_type;
  })();

  // bodyタグのDOM要素取得
  var content_obj = document.getElementsByTagName("body");

  // mecab api へリクエスト
  http.open("POST","/labs/mecab/api_kana.php",true);
  http.setRequestHeader("content-type","application/x-www-form-urlencoded;charset=UTF-8");
  http.onreadystatechange = response;
  http.send("str=" + encodeURIComponent(content_obj[0].innerHTML));

  // mecab api からレスポンスがあった時の処理
  function response(){
   if(http.readyState == 4){
    xmlObj = http.responseXML;
    var kana = "";
    for(i=0;xmlObj.getElementsByTagName('result')[i];i++){
      kana += xmlObj.getElementsByTagName('result')[i].firstChild.data;
    }

    content_obj[0].innerHTML = kana;
   }
  }

 };

所謂ajaxな処理フローなわけですが、ポイントが二つあります

  1. リクエストする際のメソッドはGETではなくPOST
  2. 投げるhtmlのURLエンコードにはencodeURIComponent関数を利用

1.に関して、投げるパラメータの容量が大きいことから、GETでは容量オーバーしてしまいます。そこでPOSTを利用するのですが、openメソッドの第1引数の”GET”を”POST”に変えただけでは動作しません。変更点は以下。
■GETだと・・・

 http.open("GET","/labs/mecab/api_kana.php?str=" + encodeURIComponent(content_obj[0].innerHTML)",true);
 http.onreadystatechange = response;
 http.send(null);

で、動くのですが、strの値が長すぎると動作しなくなります。
■これをPOSTに変更する場合、

 http.open("POST","/labs/mecab/api_kana.php",true);
 http.setRequestHeader("content-type","application/x-www-form-urlencoded;charset=UTF-8");
 http.onreadystatechange = response;
 http.send("str=" + encodeURIComponent(content_obj[0].innerHTML));

と、setRequestHeaderメソッドでリクエストヘッダの指定と、sendメソッドでの変数の指定が必要になります。

次に2.についてですが、始めurlエンコード用にencodeURIComponentではなくencodeURIを使っていたのですが、これだと変換されたカナが途中までしか帰ってきませんでした。
たとえばリクエストパラメータの内容が「html_start_hoge&huga=html_end」とすると、リクエスト内容は、

str=html_start_hoge&huga=html_end

になりますが、
■encodeURIの場合

str=html_start_hoge&huga=html_end

とこのままなので、strの値はhtml_start_hogeまでと認識されてしまいます。
■encodeURIComponentの場合

str=html_start_hoge%26huga%3Dhtml_end

これで投げたい内容がすべてstrの内容として認識されます。
「&」のエンコードをするのがポイントですね。
そして、最後にこのchangeKANAをクリック時に呼び出すようにセットします。

<a onclick="changeKANA();return false;" href="">すべてがカナになる</a>

mecab api

htmlを受け取ってカナにする処理ですが、ポイントが一つ。

  • 受け取ったhtmlからタグを除いた部分をmecabに解析させる

mecabにタグまで投げちゃうと、記号から何からきれいに分割される意味のない処理が走りますので、そこは除いて、文章のみを解析させます。そのためには、まず、受け取った文字列からタグの部分とそうでない部分を分ける必要があるのですが、その部分のスクリプトが以下

 $str = $_POST["str"];
 $str = urldecode($str);
 preg_match_all('/<("[^"]*"|'[^']*'|[^'">])*>/',$str,$tags,PREG_PATTERN_ORDER);
 $split_strs = preg_split('/<("[^"]*"|'[^']*'|[^'">])*>/',$str);

正規表現は、こちらを参考にさせていただきました。
phpの正規表現 – HTMLタグを消去するメモ:読断と変見

で、htmlタグを、タグだけの$tags配列とタグを除いた$split_strs配列に分割してるんですが、なんか、こうもっとスマートにできそうな気がw 正規表現があまり得意ではないもんで、とりあえずこれでw
これであとは、しりとるの文字解析の要領でカナ変換結果がxml形式で得られます。それを、上記javascriptのこの部分で、受け取った結果を反映させます。

    var kana = "";
    for(i=0;xmlObj.getElementsByTagName('result')[i];i++){
      kana += xmlObj.getElementsByTagName('result')[i].firstChild.data;
    }

    content_obj[0].innerHTML = kana;

09/05/12 追記)firefox3で、xmlObj.getElementsByTagName(‘result’)[i].firstChild.data が一定の長さ以上の文字列をカットしていることが判明したので、分割して返すように処理を変更

すべてがカナになる、の名前

この名前についてですが、これまた、最近読んだ「すべてがFになる」という本から影響受けてますw
これシリーズ化できそう・・・w

タグ: , ,

関連があるかもしれないエントリー

コメントをどうぞ