文をMeCabで単語に分解して、json として返す処理を作ったところ、to_json すると、すべての単語が \\ufffd になってしまうという問題が発生した。
MeCabが返す string に str.force_encoding(Encoding::UTF_8) とすると、ちゃんと to_json することができた。
以下の処理では文字がすべてつぶれてしまう。。
ruby-1.9.2> m = MeCab::Tagger.new ruby-1.9.2> p m.parse("先週、川崎フロンターレの試合を見に行ったけど、選手がほとんど分からなかったぞ。").split("\n").map{|w| w.split(",")[0].split(' ')[0] }.to_json "[\"\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\",\"\\ufffd\\ufffd\\ufffd\",\"EOS\"]"
str.force_encoding(Encoding::UTF_8) することで、正しい文字列の集合を得ることができた
ruby-1.9.2> m = MeCab::Tagger.new ruby-1.9.2> p m.parse("先週、川崎フロンターレの試合を見に行ったけど、選手がほとんど分からなかったぞ。").split("\n").map{|w| w.split(",")[0].split(' ')[0].force_encoding(Encoding::UTF_8) }.to_json "[\"\\u5148\\u9031\",\"\\u3001\",\"\\u5ddd\\u5d0e\",\"\\u30d5\\u30ed\\u30f3\\u30bf\\u30fc\\u30ec\",\"\\u306e\",\"\\u8a66\\u5408\",\"\\u3092\",\"\\u898b\",\"\\u306b\",\"\\u884c\\u3063\",\"\\u305f\",\"\\u3051\\u3069\",\"\\u3001\",\"\\u9078\\u624b\",\"\\u304c\",\"\\u307b\\u3068\\u3093\\u3069\",\"\\u5206\\u304b\\u3089\",\"\\u306a\\u304b\\u3063\",\"\\u305f\",\"\\u305e\",\"\\u3002\",\"EOS\"]"
なんで???
ruby 1.9 では Stringが文字コード情報を持っているということで、 str.encoding で文字コード情報を確認
ruby-1.9.2-p180 :020 > m.parse("先週、川崎フロンターレの試合を見に行ったけど、選手がほとんど分からなかったぞ。").split("\n").map{|w| p w.split(",")[0].split(' ')[0].encoding } #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT> #<Encoding:ASCII-8BIT>
MeCab はStringを ASCII で返している。。
なので、文字列はそのままで、文字コード情報をUTF-8 に変換してあげる必要があるようですね。
force_encodingメソッドは、文字列の文字コード情報を引数encodingに切り替えます。引数には文字列かEncodingオブジェクトを指定します。レシーバ自身を変更するメソッドです。戻り値はレシーバ自身です。
force_encodingメソッドは文字コード情報を変更しますが、文字列が持っているバイト列は変更しません。一般的な意味で「文字コードの変換」を行いたいときは、encodeメソッドを使います。
参考: