- blogs:
- cles::blog

ISO-2022-JP と CP50220 と Encoding::UndefinedConversionError


Ruby は 1.9 から文字エンコード周りが変更されているので、先月も Encoding::CompatibilityError ではまってしまいましたが、今回は Encoding::UndefinedConversionError というエラーにどっぷりはまってしまいました。メールスプールのファイルを読み込むプログラムが書きたかったのですが、メールが厄介なのはファイルを開いてヘッダを調べてみないと文字コードが判別できないということです。バイト列から文字コードを自動的に検出すればいいのかもしれませんが、それはそれで結構手間がかかる*1ようです。
具体的に躓いたのは下記のような、所謂機種依存文字を含むようなメールでした。
test.eml
† ISO-2022-JP じゃなくて CP50220 を使おう
結論だけ最初に述べると、メールのヘッダで ISO-2022-JP と指定されている場合には、Ruby ではエンコーディングとして CP50220 を使う必要があるということです。
これはちょうど Shift_JISとCP932 の違いの話の ISO-2022-JP 版ですね。
以下、作業メモ
† ASCII-8BIT の罠
Ruby ではバイナリモードでファイルを読み込むと Encoding::ASCII_8BIT になります。
エンコードが Encoding::ASCII_8BIT の状態だと encode! に何を渡してもエラーを吐かず、変換もされないようです。
具体的には、下記のコードを実行すると、gsub! がちゃんと機能せず、表示すると内容が JIS のままということが分かります。
hoge1.rb
※最後の行は文字化けしています。
† force_encoding を使って文字コードを設定してみる
String の中身を変更せずに、エンコーディングの認識だけを強制的に変更するには、 String#force_encoding*2 を使えばよいので、プログラムを少し書き換えて、メールのヘッダ部分から charset=ISO-2022-JP のような部分を探して、その部分のエンコードを設定してやることにします。(本当はもうちょっとまともなコードを書きましたが、ここでは大幅に簡略化しています。)
hoge2.rb
これで一件落着かと思っていたのですが、ところが今度は Encoding::UndefinedConversionError が出て動きません。
エラー中の "\xAD\xA1" という部分は ① にあたる部分のようです。
† CP50220 をつかうことに
上記のエラー自体は①がUTF-8に変換出来ないというのは分かるのですが、わざわざヘッダで指定されている文字コード(ISO-20220-JP)を指定すると変換エラーでコケるという動作がイマイチ腑に落ちません。そのまましばらく悶々としていたのですが、冷静になってよく考えてみると、昔、Shift_JISとCP932 の違いの話とか、EUC-JP と EUC-JP-ms の違いでハマったことを思い出したので、 ISO-2022-JP のMS仕様があるのではと思って調べてみたところこれがビンゴでした。
cp50220 - Legacy Encoding Project
Windows Codepage 50220
Windows での ISO-2022-JP の一種
Outlook Express, Internet Explorer で使われている
Unicode から cp50220 への変換時に、JIS X 0201 片仮名は JIS X 0208 の片仮名に置換される
想定する使用用途
Outlook Expressが送ってきたメールを①(まる1)などの、拡張文字も含めて正しく処理したいとき
ということで、 Encoding を調べてみると Encoding::CP50220*3 というのがあったので、これを使ってみます。
hoge3.rb
これでやっと望む動作になりました。
メールのヘッダに ISO-2022-JP と書いてあったり、SJIS と書いてあるときは要注意なんですね。
苦労しましたが、今回の件でRuby 1.9 のエンコード周りはかなり理解できました。
- *1: Ruby 1.9で文字コードの自動判別を行う - @masuidrive blog
- *2: instance method String#force_encoding
- *3: constant Encoding::CP50220
このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/4990
古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
コメントは承認後の表示となります。
OpenIDでログインすると、即時に公開されます。
OpenID を使ってログインすることができます。
2 . 福岡銀がデマの投稿者への刑事告訴を検討中(112950)
3 . 年次の人間ドックへ(112376)
4 . 2023 年分の確定申告完了!(1つめ)(111945)
5 . 三菱鉛筆がラミーを買収(111819)