■2010-04-06
* [Perl][メモ] JSONのドキュメントに追加した部分
tokuhiromさんに(en|de)code_jsonと(to|from)_jsonどっちを使ったほうが良いのか初心者にわかるようにしたらと言われたので、最近のJSON.pmのドキュメントには(en|de)code_jsonがオススメである旨が付け足されています。さらに念を押して、一応自分ではわかりやすく説明したつもりの"HOW DO I DECODE A DATA FROM OUTER AND ENCODE TO OUTER"というセクションが加わっています。
で、この日誌にperl json 文字化けとかで検索してくる人がたまにいて、たぶんこのページがヒットするのでしょうが、(自分で訳しておいて何ですが)これ見てもわかりにくいんじゃないかなあという気がします。また、先のgoogleの検索結果のトップには現状Kawa.netさんの2008年初頭のページが最初の方に表示されますが、UTF8フラグ云々の話が書いてあって初心者向けじゃないと思うので、何かの参考になるかもしれないので"HOW DO I DECODE A DATA FROM OUTER AND ENCODE TO OUTER"の和訳を掲載しておきます。
※PerlとUNICODEについてはこの辺りでperluniから始まるファイルを読んでみてください。
どのように外部からのデータをdecodeするか、外部へとencodeするか
このセクションはPerl5.8以降を想定しています。
もし外部(ネットやファイルなど)からきたJSONデータがUTF-8でエンコードされてるのがわかっているなら、decode_jsonかutf8オプションを有効にしたJSONオブジェクトを使うべきです。decodeされた結果はUNICODEキャラクタを含んでいるでしょう。
# ネットから my $json = JSON->new->utf8; my $json_text = CGI->new->param( 'json_data' ); my $perl_scalar = $json->decode( $json_text ); # ファイルから local $/; open( my $fh, '<', 'json.data' ); $json_text = <$fh>; $perl_scalar = decode_json( $json_text );
もし外部データがUTF-8でないなら、まずはそのデータをdecodeします。
use Encode; local $/; open( my $fh, '<', 'json.data' ); my $encoding = 'cp932'; my $unicode_json_text = decode( $encoding, <$fh> ); # あるいは下のように # # open( my $fh, "<:encoding($encoding)", 'json.data' ); # $unicode_json_text = <$fh>;
この場合、$unicode_json_textはもちろんUNICODEな文字列です。ですから、decode_jsonやutf8オプションを有効にしたJSONオブジェクトは使えません。代わりに、utf8オプションを無効にしたJSONオブジェクトか、from_jsonを使います。
$perl_scalar = $json->utf8(0)->decode( $unicode_json_text ); # または $perl_scalar = from_json( $unicode_json_text );
あるいはencode 'utf8'してからdecode_jsonします。
$perl_scalar = decode_json( encode( 'utf8', $unicode_json_text ) ); # 効率的ではない
今度は、$perl_scalarをJSONデータに変換して外部(ネットやファイルなど)へと送ります。
通常あなたのデータはUNICODE文字列を含んでいます。UTF-8でエンコードされたJSONデータにするなら、encode_jsonかutf8オプションを有効にしたJSONオブジェクトを使うべきです。
print encode_json( $perl_scalar ); # または print $json->utf8->encode( $perl_scalar );
何らかの理由で$perl_scalarがUNICODEではなく$encodingでエンコードされた文字列を含んでいる場合、そのキャラクタはlatin1とみなされます(perlはあなたの$encodingを気にしません)。encode_jsonやutf8オプションを有効にしたJSONオブジェクトは使えません。代わりにutf8オプションを無効にしたJSONオブジェクトか、to_jsonを使います。この結果生成されるテキストはUNICODEですが、出力しても問題ありません。
# $perl_scalarは$encodingでエンコードされた値を持つ $unicode_json_text = $json->utf8(0)->encode( $perl_scalar ); # または $unicode_json_text = to_json( $perl_scalar ); # $unicode_json_textは0x100未満のキャラクタで構成されている print $unicode_json_text;
あるいは文字列を全部deocde $encodingしてからencode_jsonする:
$perl_scalar->{ foo } = decode( $encoding, $perl_scalar->{ foo } );
# 全部の内容にたいして上記操作を……
$json_text = encode_json( $perl_scalar );
この方法は適切ではありますが、たぶん効率悪いです。
Encodeやperluniintroを参照してください。

