MacJapanese, CP932, Shift_JIS の違いと Ruby での取り扱い


前置き

 文字コードに混乱させられて酷い目にあったので、犠牲者を減らすため整理しました。3つの文字コードについての話題です。Shift_JIS (http://ja.wikipedia.org/wiki/Shift_JIS), MacJapanese (http://ja.wikipedia.org/wiki/MacJapanese), CP932 (http://ja.wikipedia.org/wiki/Microsoftコードページ932) の違いについてまとめます。また、それらを Ruby で扱う際の注意点について説明します。

MacJapanese, CP932, Shift_JIS の違い

 上にあげた3つの文字コードは文字-バイト列の変換方式であり、文字-バイト列の対応表でもあります。いずれも同じ変換方式を使いますが、持っている対応表が異なります。この中では Shift_JIS の対応表が最も小さなものになります。MacJapanese, CP932 は Shift_JIS の対応表をそれぞれ独立に拡張したものです。たとえば文字 は Shift_JIS, MacJapanese, CP932 のどれでも 0x82A0 に対応します。しかし文字 (ローマ数字の1) は Shift_JIS には存在せず、MacJapanese では 0x859F であり、 CP932 では 0x8754 に対応します。表にすると下のようになります。

Shift_JIS MacJapanese CP932
0x82A0 0x82A0 0x82A0
ローマ数字の1 無し 0x859F 0x8754

ローマ数字のⅠ,Ⅱ,Ⅲ... の他に囲み文字 ①,②,③... もそれぞれ異なるバイト列になります。

MacJapanese が使われているアプリケーション

 ほとんど見かけないのですが、絶滅しているわけではありません。Microsoft Excel のファイル *.xls または *.xlsx を Mac 版 Office で CSV 出力すると MacJapanese になります。Windows 版 Office で同じ操作をすると CP932 の CSV ファイルが出力されます。非常にややこしいですね。また、Mac 標準のメーラーも MacJapanese を使っているようです。

Ruby での取り扱い

 Ruby で Shift_JIS, CP932, MacJapanese のファイルを読み込むことを考えます。Shift_JIS や CP932 であれば、File.read("hoge.txt", encoding: 'CP932') のように引数で文字コードを指定すれば良いので問題ありません。

 ところが MacJapanese の場合は文字コードを指定してもエラーになります。なぜならば、Ruby は MacJapanese の変換表を持たないためです。たとえば "あ".encode("MacJapanese") を実行すると Encoding::ConverterNotFoundError が発生します。(そのスクリプト自体を MacJapanese で書けばエラーは起こらないかもしれません)

 最も良い方法は、MacJapanese で書かれたファイルを仕様から外すことです。与えられたファイルが Shift_JIS か MacJapanese か CP932 かを判断するのは困難ですし、ファイルを作成したユーザさえそのことを知らないのが普通です。MacJapanese が作られる状況は限定的ですので「Mac 版エクセルを使用しないでください」で事足りる場合も多いと思います。

 次善策として、全てのファイルを Shift_JIS として扱う方法があります。この方法は、ほとんどの文字に対して、期待した結果が得られます。もちろん、文書中に①などの文字が使われている場合、簡単にはいきません。たとえば "①".encode("Shift_JIS")Encoding::UndefinedConversionError を発生させます。この例外を rescue して、無効な文字に置き換えるか、ユーザに訂正を促すなどの対処が必要です。ただこの場合は CP932 も引っかかってしまうので、傷口が広がってしまうかもしれません。