RJSONIOでUnicode文字列を扱えるようにしてみた

R で JSON を扱うには rjson か RJSONIO がありますが、前者はすぐに落ちるし、後者はバージョン0.4以降 Unicode文字列が扱えないという状況で、実質 R では JSON を扱えません。
twitteR では RJSONIO を使って JSON をパースしているため、twitteR で日本語のツイートを取得するためにはわざわざ RJSONIO 0.3 をダウンロードして手動インストールしなければなりません。

けしからんですね!!

というわけで C/C++ をまともに読むことすらできないのに RJSONIO で Unicode文字列を扱うためのパッチを作成しました。
patch for RJSONIO_0.96-0 ― Gist

パッチを適用して使ってみる

現状把握

とりあえず現状の酷さを確認しておきます

$ R
> install.packages("RJSONIO")
> library(RJSONIO)
> # "あいうえお"
> fromJSON("[\"\\u3042\\u3044\\u3046\\u3048\\u304A\"]")
[1] "BDFHJ"

これはひどいっ!”あいうえお” と表示されませんね!

パッチの適用

$ wget https://raw.github.com/gist/1556388 -O RJSONIO_0.96-0.patch # パッチのダウンロード
$ wget http://cran.r-project.org/src/contrib/RJSONIO_0.96-0.tar.gz  # RJSONIO アーカイブのダウンロード
$ tar xvfz RJSONIO_0.96-0.tar.gz
$ patch -p1 -d RJSONIO < RJSONIO_0.96-0.patch 
patching file src/libjson/JSONOptions.h
patching file src/rlibjson.c
$ sudo R CMD remove RJSONIO   # RJSONIO(バグってるやつ)のアンインストール
$ sudo R CMD install RJSONIO  # RJSONIO(パッチを当てたやつ)のインストール

実行してみます

$ R
> library(RJSONIO)
> # "あいうえお"
> fromJSON("[\"\\u3042\\u3044\\u3046\\u3048\\u304A\"]")
[1] "あいうえお"

おおぉぉぉ、ちゃんと “あいうえお” と表示されましたね!!

仕組み

RJSONIO で Unicode文字列が扱えなくなったのは JSONをパースするライブラリを変更したからみたいです。
0.4以降からはlibjsonを使うようにしたみたいなんですが、libjson で Unicode文字列を扱うにはビルド時に libjson/JSONOptions.h の

//#define JSON_UNICODE

となっている部分のコメントアウトを解除しなければなりません。

Unicode文字列を変換する際には

  1. static_cast(internalJSONNode) (つまり internalJSONNode::operator json_string())
  2. internalJSONNode::Fetch
  3. internalJSONNode::FetchString
  4. JSONWorker::FixString
  5. JSONWorker::SpecialChar
    と処理されていくのですが、JSON_UNICODEが定義されていると JSONWorker::UTF –> JSONWorker::UTF8 へと処理が渡り、定義されていないといきなり JSONWorker::UTF8 へと処理が渡ります。
    これが Unicode文字列を正しくパースするかどうかのポイントです。

っで、JSON_UNICODE を定義すると json_char の型が char* から wchar_t* に変わるので、それに対応させる処理を加えないといけません。
そんなわけで RJSONIO の rlibjson.c を書き換えているんですが、C言語とか全然知らないのでおそらくひどい書き方だと思います・・・

去年RJSONIOの作者にUnicode文字列が扱えないってバグ報告した時は無視されましたが、今度はパッチまで作ったんで何らかの対処をしてくれるでしょう。
これでようやく R でも JSON が扱えるようになるんじゃないですかね!!