ぱろっと・すたじお

技術メモなどをまったりと / my site : http://parrot-studio.com/

Ruby1.9でEUC-JPの機種依存文字を処理する

※本記事は自鯖Blogの転載です
※元記事は2012/10/15に書かれました

http://blog.parrot-studio.com/2012/10/ruby19-euc-cp51932/


古いシステムがEUC-JPで動いていて、
そこからのリクエストをRubySinatra(あるいはPadrino)で受ける・・・

・・・そんなこと、よくありますよね(´・ω・)? *1

文字コードの変換は面倒なもので、ここがネックになることが多いのですが、
携帯絵文字まで対応しているRuby1.9系ならきっと大丈夫

・・・そんな風に考えていた時期が私にもありましたΣ(・ω・ノ)ノ

[1] pry(main)> RUBY_VERSION
=> "1.9.3"
[2] pry(main)> ''.encoding
=> #<Encoding:UTF-8>
[3] pry(main)> ''.encode('EUC-JP')
=> "\x{A4A2}"
[4] pry(main)> ''.encode('EUC-JP').encode('UTF-8')
=> ""

ここまではいいんですよ
問題は「機種依存文字」の場合でして

[5] pry(main)> ''.encoding
=> #<Encoding:UTF-8>
[6] pry(main)> ''.encode('EUC-JP') 
Encoding::UndefinedConversionError: U+2460 from UTF-8 to EUC-JP
from (pry):6:in `encode'

この文字にマッピングがないのは「文字コードの仕様」です
なので、これはある意味で正常な動作です

バイナリ表現をしてもダメです(´・ω・`)
("\xAD\xA1"は「丸に1」のEUC-JPバイナリコード)

[7] pry(main)> "\xAD\xA1".encode('EUC-JP')
Encoding::InvalidByteSequenceError: "\xAD" on UTF-8
from (pry):7:in `encode'

そもそもそんなコードはUTF-8の範囲にないといわれますが、
ブラウザから送られてくる文字列にこれが含まれているわけです
さて、どうしたものか・・・

ここで引っかかっていろいろ調べた結果、
EUC-JP」と呼ばれるものにもいろいろ種類があると判明

wikipedia:EUC-JP

Shift_JIS」と呼ばれるものが、実際には「CP932」だったりするように、
EUC-JP」と呼ばれるものの「正式な名前」が他にあるはず、ということです

そこで、Rubyのリファレンスとにらめっこしたところ・・・

http://doc.ruby-lang.org/ja/1.9.3/class/Encoding.html

・・・「CP51932」というのが実に怪しいわけでございます

早速encodeしようとすると・・・

[8] pry(main)> "\xAD\xA1".encode(Encoding::CP51932)
Encoding::InvalidByteSequenceError: "\xAD" on UTF-8
from (pry):8:in `encode'

・・・ダメですΣ(゚Д゚)ガーン

「"\xAD\xA1"」という文字列にUTF-8のEncodingが付加されているので、
force_encodingで解釈し直さないとダメです

ちなみに、Sinatra(Rackの仕様かも?)が
EUC-JPのフォームからリクエストを受け取る場合、
文字列にUTF-8のEncodingを付加するため、同じ現象が起きます

ということで・・・

[9] pry(main)> "\xAD\xA1".force_encoding(Encoding::CP51932)
=> "\x{ADA1}"
[10] pry(main)> "\xAD\xA1".force_encoding(Encoding::CP51932).encode('UTF-8')
=> ""
[11] pry(main)> ''.encode(Encoding::CP51932).encode('UTF-8')
=> ""

・・・レガシーなシステムからのリクエストだって大丈夫
そう、Ruby1.9ならね(`・ω・´)

なお、この仕組みを実装したシステムで動作確認したところ、
MacのChrome/OperaWindows7IE9/Chromeで正常に動いたので、
おそらく大丈夫だとは思いますが、必ずテストはしましょうね *2

*1: ねーよ!!щ(゚Д゚щ)

*2: 余談ですが、CP51932と似たようなものに、eucJP-ms(EUCJP_MS)というのもあります 基本的にどっちでもいい気がしますが、今回のシステムはメインユーザが圧倒的にWindowsのIEである点から、CP51932でいいんじゃないかな・・・とは そもそも機種依存文字というよりは丸文字を通すのが主目的なので、どちらでもいいのですが