kuromoji.jsを使って日本語クローズテスト

# クローズテストってものがあるらしい

オライリーから出ている<a href="http://www.oreilly.co.jp/books/9784873116082/" target="_blank">インタフェースデザインの実践教室</a>という本を読んでいたところ、文章のユーザビリティをチェックする為のクローズテストについて説明がありました。

簡単に説明すると一定間隔で穴が開いた状態のテキストを読んで、ユーザーが文章の意味をくみ取れるかをチェックする為のテストです。
ある程度の単語が隠れた状態でも伝わる文章を書けという事でしょうか。

詳しくはこちら
<a href="http://alistapart.com/article/testing-content" target="_blank">Testing Content · An A List Apart Article</a>

## 実装してみよう
先に上げた本の中で訳者が、日本語でUI用途の利用例が見つかれないよーと書いてあったので早速実装してみました。
また、先日から<a href="http://qiita.com/pppp403/items/698bc2a55d29d5655b97" target="_blank">JavaScriptで言語処理100本ノック2015</a>というのに取り組んでいる最中でしたので、kuromoji.js というライブラリを使いJavaScriptでの実装を行いました。

### kuromoji.jsについて
>簡単に使える Pure JavaScript の形態素解析器
<a href="http://stp-the-wld.blogspot.jp/2015/01/javascriptkuromojijs.html" target="_blank">ブラウザで自然言語処理 - JavaScriptの形態素解析器kuromoji.jsを作った</a>

という事です。凄いらしい。
早速つかってみます。

## デモ
テストの<a href="https://pppp606.github.io/closetest/" target="_blank">デモページ</a>になります。
辞書ファイルが16MBぐらいあって読み込むまで多少の時間がかかります。

<a href="https://pppp606.github.io/closetest/" target="_blank"><img src="https://qiita-image-store.s3.amazonaws.com/0/39655/d60732f8-fbe2-5733-1cf2-96fb9fab92cf.png"></a>



## ソースはこんな感じ
```js:main.js
/**
クローズテスト用 kuromojiを継承
* @class closeTest
* @method init 初期化 パラメータのセット
* @method setProblem 空白の問題文を生成
* @method check 正解率のチェック
* @property {has} data 文章データ kuromoji.jsで形態素解析済み
* @property {number} oneset oneset毎に文字を隠す
* @property {string} targetElement jqueryに渡すdomエレメント
* @property {string} DIC_URL 辞書ファイルのパス
*/
var closeTest = function(){
  this.data = {
    planText:"",
    tokenize:{}
  };
  this.oneset;
  this.targetElement;
  this.DIC_URL = "bower_components/kuromoji/dist/dict/";
  this.tokenizer;
  this.init = function(_planText,_oneset,_targetElement){
    this.data.planText = _planText;
    this.oneset = _oneset || 5;
    this.targetElement = $(_targetElement);
  }
  this.setProblem = function(){
    this.targetElement.html("");
    this.data.tokenize = this.tokenizer.tokenize(this.data.planText);
    var _wrap = $('<div>').addClass('problem');
    var k = 1;
    for (var j = 0; j < this.data.tokenize.length; j++) {
      if(k % this.oneset == 0 && this.data.tokenize[j].pos != "記号"){
        var _inputprop = {
          type:"text",
          "data-surface":this.data.tokenize[j].surface_form
        }
        _wrap.append($('<input>').attr(_inputprop).addClass('surface'));
        this.targetElement.append(_wrap);
        k++;
      }else{
        _wrap.append($('<span>').html(this.data.tokenize[j].surface_form));
        this.targetElement.append(_wrap);
        if(this.data.tokenize[j].pos != "記号"){
          k++;
        }
      }
    }
  }
  this.check = function(){
    var _problem = $('.problem input');
    var _score = 0;
    _problem.each(function(){
      if($(this).val() == $(this).attr("data-surface")){
        _score++;
      }
    });
    return Math.round(_score/$('.problem input').length*100);
  }
}
closeTest.prototype = kuromoji;


$(function(){
  var _text = $('.testWording textarea').val();
  var closetest = new closeTest();
  closetest.init(_text,6,'.closeTest');
  closetest
    .builder({dicPath:closetest.DIC_URL})
    .build(function (error, tokenizer) {
      closetest.tokenizer = tokenizer;
      closetest.setProblem();
    });

  //チェックボタンの挙動
  $('.btnWrap').on('click','.btn.active.set',function(){
    closetest.data.planText = $('.testWording textarea').val();
    closetest.setProblem();
  });
});
```
※分かり易くする為に元のソースからjqueryでのUI操作周りを削った状態です。


kuromoji.js の使い方としてはここら辺ですかね。
ここだけ見ると分かり辛いですが `closetest`は`kuromoji`を継承したクラスです。

```js
closetest
    .builder({dicPath:closetest.DIC_URL})
    .build(function (error, tokenizer) {
      closetest.tokenizer = tokenizer;
      closetest.setProblem();
    });
```

`builder().build()`で準備が整った後、コールバックで処理をしています。
`kuromoji`で解析した結果は、一単語に対してこんな感じのキー配列で帰ってきます。

```js
{
  basic_form:"吾輩",
  conjugated_for:"*",
  conjugated_type:"*",
  pos:"名詞",
  pos_detail_1:"代名詞",
  pos_detail_2:"一般",
  pos_detail_3:"*",
  pronunciation:"ワガハイ",
  reading:"ワガハイ",
  surface_form:"吾輩",
  word_id:957200,
  word_position:1,
  word_type:"KNOWN"
}
```

少しも難しい事がなく実装できました。

## まとめ
kuromoji.jsが凄い。

あと自分で書いた文章でも、流し込んでテストをしてみると結構理解出来ない状況になります。
分かり易い文章を書くために有用なテストだと思いました。

それから何単語毎に削るのかとか固有名詞の場合は空白にしないとか、もう少し考えるとテストの精度が上がりそうですね。
そのうち直してみます。

ソースは<a href="https://github.com/pppp606/closetest" target="_blank">github</a>にも置いて有ります。