Shift_JISと死の文字化け
はじめに
この授業は闇の魔術に対する防衛術の21時限目です。
Windowsが覇権を握る現代社会では、たとえLinuxやmacOSユーザでもShift_JISに関わらずに生きることは非常に困難です。*1
さらに他の文字コードと異なりWindowsでは正しく表示されるが、なぜかLinuxに持ってきたとたん(主に苗字が*2*3)マッハで化けてフロアが不夜城と化すことも珍しくありません。
そんな闇の魔術ことShift_JISと正しく戦う術を皆さんと共有出来たらと思います。
Shift_JIS is 何?
そもそもShift_JISとは何でしょう。はい、ハーマイオニー
JIS X 0201とJIS X 0208を符号化文字集合とした文字符号化方式(エンコーディングスキーム)*4
素晴らしい。
知らない単語が幾つか出てきましたので、一つずつ確認していきましょう。
ちなみにShift_JISであって、Shift-JISではありません。今後間違えるごとに5点ずつ減点です。
符号化文字集合と文字符号化方式
厳密に言ってしまうと『文字コード』という用語が持つ意味はその『文字コード』が登場する文章のコンテキストに依存します。つまり、定義が無くみんなが思い思いにフワッと使用してるに過ぎません。
いわゆる文字コードは以下の用語のどちらかもしくは両方を指す用語として使用されることが多いです。
- 符号化文字集合
- 文字を集めて整理して表にまとめ(文字集合)、表にまとめた文字に一意なコードを振る(符号化)
- 例
- JIS X 0201『7ビット及び8ビットの情報交換用符号化文字集合』
- JIS X 0208『7ビット及び8ビットの2バイト情報交換用符号化漢字集合』
- Universal Coded Character Set
- 文字符号化方式(エンコーディングスキーム)
ただ、JIS X 0201やJIS X 0208は規格中で文字符号化方式も規定しているので文字符号化方式でもあります。が、実際使われているかと言うとほとんど使われていない*6ので符号化文字集合として扱います。
ちなみに、UnicodeはUCS(Universal Coded Character Set(符号化文字集合))とUTF(Unicode Transformation Format(文字符号化方式))等を含んだ規格の名称です。
JIS X 0201
規格名は『7ビット及び8ビットの情報交換用符号化文字集合』でISO/IEC 646に準拠した規格となります。
ASCII文字*7にいわゆる半角カタカナを追加した文字集合です。
まぁ、こちらは特に複雑な事もないので軽くスルーしましょう。
JIS X 0208
規格名は『7ビット及び8ビットの2バイト情報交換用符号化漢字集合』で、何気に世界初のマルチバイト符号化文字集合で結構凄いやつなんです。
で、この情報交換用というのが厄介で、『高』『髙』、『神』『神』のように意味の同じで異なる字体*8を包摂の概念の元、規格としては同じものとして扱うことになっています。
髙田さんや神崎さんは激おこぷんぷん丸かもしれませんが、現実問題そうしないと規格として定義する文字が膨大になり規格に準拠するコストが爆上げになります。*9
つまり、『高』と『髙』、『神』と『神』はJIS X 0208の規格上は等価です。また、『﨑』は収録されていないため『崎』で代用するほかありません。*10
また、JIS X 0208には符号空間に空きがあり、当事者間で合意がとれていれば空いている空間に任意の文字を追加することが出来ます。
Shift_JISとCP932
CP932はWindows上でのShift_JISの実装になります。つまり、Windows上でShift_JISというとCP932を指すことになります。
で、歴史的な背景*11があり幾つかの文字が追加されています。 はい、そうです。『髙』や『﨑』などの漢字、また『①』のような丸付き数字は純粋なShift_JISでは表現できないCP932(JIS X 0208)に独自に追加された文字なのです。
つまり、Windows上で追加文字を含むテキストファイルを作成し、それをLinux等に転送後にShift_JISとして解釈させると化けます。
対策
じゃあどうすればいいのでしょうか。
例えばWindows⇒Linuxとデータをやり取りする場合を考えてみましょう。 すると以下のパターンが考えられます。
- そもそもShift_JISとして転送しない(最初から最後までUTF-8等のUnicodeを使用する)
- 強い意志でCP932の追加文字を使わない・使わせない(Shift_JISを使用することの当事者間の合意を形成する)
- すべての闇を受け入れてCP932を使用する(CP932を使用することの当事者間の合意を形成する)
『﨑』等の追加文字を使用しなければLinux側でShift_JISとして解釈しても化けることはありません。 が、これはビジネス要件に依存する上にステークホルダーを納得させるのは割と難しいです。
UTF-8等のUnicodeを使用すればCP932の追加文字も正しく扱える上に、平成も終わる今日では一般的な文字コードですのでLinux側の対応もしやすいです。 ただ、Windows側でUTF-8に対応してない等の事情があると使えません。(ExcelのCSVとかExcelとかExcelとか)
最終手段としてLinux側でもCP932を正しく扱えるように頑張るというのがありますが、こちらはnkfを処理のパイプラインに挟む等の対策ぐらいしか思い浮かびません。
おわりに
結論を申しますとUTF-8で全人類は救済される*12し、マイクロソフトはExcelにPythonを載せる前にやるべきことがあるといったところで今日の授業は以上となります。
明日の授業は@----_先生です。楽しみですね
おまけ
全角・半角文字とEUC-JP
ここからはちょっと余談なのですが、よく全角カタカナと半角カタカナの違いについて、
1バイトで表現されるのが半角カタカナ、2バイトで表現されるのが全角カタカナ
と説明されているのを見かけますが、残念ながらそれはShift_JISでしか成り立ちません。
EUC-JPでは半角カタカナ・全角カタカナ共に2バイトで表現されますし、UTF-8では半角カタカナ・全角カタカナ共に3バイトで表現されます。
UTF-16に至ってはすべての文字が2バイトもしくは4バイトで表現されます。
メモ帳の『ANSI』
メモ帳の文字コードには『ANSI』なる謎文字コードで保存できるオプションがあります。
歴史的な経緯等は原典を見つけられなかったのですが、『ANSI』はそのロケールの既定の文字コードを表す単語らしく日本語だとShift_JIS(CP932)を表します。
他のロケールのWindowsですとそれぞれのロケールの既定の文字コードを表すので注意が必要です。
参考書籍
文字コード超研究 改訂第2版 深沢千尋
JIS X 0208 『7ビット及び8ビットの2バイト情報交換用符号化漢字集合』
*2:名前は戸籍法の施行規則で常用漢字表と人名用漢字表に限定されているのでマイナーな漢字が入ることはあまりないのですが、苗字は手書きの戸籍の名残で字体が崩れたのがそのまま文字として認識されてしまった等の経緯でマイナー漢字の宝庫と化します
*3:さらに文化的な側面もあるので苗字に使用可能な漢字を法律等で規制するというのはかなり困難です
*4:JIS X 0208の代わりにJIS X 0213を使用するShift_JIS-2004という文字コードもありますが、従来のShift_JISと互換性が失われる上にUnicodeに対しての優位性も無いので流行っていません。
*5:Unicodeでは符号化形式および符号化スキームを厳密に区別していますが、その辺のガチの定義は仕様書をさんしょうしてくださいよろしくおねがいします
*6:私は使用例を知らないので知っている人はコメントください
*7:厳密にいうと記号が少し違うが、ISO/IEC 646は記号を置き換えることを許している
*8:定義で言うと『図形文字の図形表現としての形状についての抽象的概念』、平たく言うと文字を頭の中に思い浮かべたときの思い浮かべた文字の事
*9:法務省の戸籍統一文字はこのような戸籍で登録されている文字を正確に扱うために策定されています。見てもらうと分かりますが結構すさまじいことになっています。
*10:『﨑』はJIS X 0208の包摂基準には記述が無いのでおそらく包摂ではないです
*11:気になる人は参考書籍を買って読んでください
*12:と言いたいところなのですが、こちらはこちらでCJK統合漢字のアレソレや、近年のハイカオス絵文字・異体字セレクタなどでこちらもなかなかの闇です。