シフトJIS / EUC-JPとUnicodeとの妥当な変換表

2004.10.17 新規作成。2004.12.19 加筆。2005.04.02加筆。

最近、コンピュータで扱う文字列の文字コードがUnicodeでなければならない場面が増えてきた。UnicodeとシフトJIS、EUC-JPを変換する機会が多い。この変換は変換表で行うが、変換表が実際的なものでなければ、文字化けが発生することになる。

おかしな変換表は、これまでは、特にLinuxなどの上で動作するオープンソースソフトウェアで多く見られた。おそらく規格原理主義者が多かったためだろう。そもそも、規格どおりに変換表を作ると、実用的な変換表にはならない。しかし、最近ではまともな変換表を実装しているものも増えてきて、うまく選ぶだけでいいようになってきている。

ソフトウェアごとの変換表とその違いをまとめたページはよく見かけるが、では実際にどのように変換するものを選べばいいか不明なので、まとめてみた。

変換表に求められる条件

このページでは、「文字」を単にコードポイントが与えられて一意に区別できるもの、ぐらいの意味で使う。包摂規準がどうあるべきか、あるいは本質的にコンピュータでの文字とは何であるか、などについては立ち入らない。

実際的な変換表は、できるかぎりround-trip conversionを達成し、なおかつ、異なるシステム上のソフトウェアとの情報交換を考慮したもの、ということになる。

Unicodeと、シフトJIS、EUC-JPとの妥当な変換表は、少なくても次の点を満たしていなければならない。

収録する文字集合と変換

  1. 0x00〜0x7F のそれぞれの文字について、U+0000〜U+007F (C0 Controls and Basic Latin; JIS X 0211 C0集合 + ISO/IEC 646 IRV) に相互に変換できること。これ以外の文字がU+0000〜U+007Fに変換されないこと。

    0x5C をU+00A5 YEN SIGN に変換してしまうと、内部Unicodeなプログラミング言語などで、この文字がバックスラッシュとして扱われない。次の表で、真ん中の列のように変換しては不味い。

    シフトJIS / EUC-JPUnicode(誤り)Unicode(妥当)
    0x7E U+203E OVERLINE U+007E TILDE
    EUC-JP 0xA1C0 U+005C REVERSE SOLIDUS U+FF3C FULLWIDTH REVERSE SOLIDUS
    EUC-JP 0x8FA2B7 U+007e TILDE U+FF5E FULLWIDTH TILDE
  2. ISO/IEC 646 IRV、JIS X 0201カタカナ、JIS X 0208漢字集合に含まれる文字をすべてUnicodeの別のコードポイントに変換し、かつシフトJIS、EUC-JPに戻したときにすべて元のコードポイントに戻ること。

    IRVとJIS X 0208には同じ文字(例えばスラッシュ'/')が含まれ、またJIS X 0201とJIS X 0208にも同じ文字が含まれている(カタカナ)。本来は文字ではなく書式の話だが、現実には、JIS X 0208は全角として、JIS X 0201は半角として表示するように期待されているので、別の字として扱う必要がある。

  3. NEC特殊文字、IBM拡張文字、NEC選定IBM拡張文字をサポートしていること。

    丸囲み数字などが含まれた、既存の大量の文書を捨てるわけにはいかない。IBM拡張文字についても同じ。round-trip conversionを維持すること。

  4. JIS X 0212補助漢字、JIS X 0213漢字集合

    JIS X 0212補助漢字、あるいはJIS X 0213漢字集合(これはJIS X 0208と互換性がない。)は、現段階ではサポートする必要はないと思う。

多重符号化された文字の扱い

ところで、NEC特殊文字にはJIS X 0208に含まれる文字があり(多重符号化)、NEC選定IBM拡張文字もIBM拡張文字と被っている。

文字集合内容コードポイント
NEC特殊文字丸囲み数字、記号などシフトJISで0x8740〜0x879c、EUC-JPで0xADA1〜0xADFC
NEC選定IBM拡張文字漢字、ローマ数字などシフトJISで、0xed40〜0xeefc
IBM拡張文字漢字、ローマ数字、(株)、No.などシフトJISで0xfa40〜0xfc4b、EUC-JPで0x8FF3F3〜0x8FF4FE

これらについては、プライベート領域 (Private Use Area; PUA, U+E000〜U+F8FF) などを駆使して別の文字に変換する手もあるが、他システムとの情報交換を考慮すると、round-trip conversionを放棄し、次のように変換したほうがいい。

  1. NEC特殊文字のうちJIS X 0208にもある文字は、Unicodeからの変換ではJIS X 0208のほうへ変換する。
    シフトJISUnicode シフトJIS名称
    0x8790 -> U+2252 -> 0x81e0APPROXIMATELY EQUAL TO OR THE IMAGE OF
    0x8791 -> U+2261 -> 0x81dfIDENTICAL TO
    0x8792 -> U+222b -> 0x81e7INTEGRAL
    0x8795 -> U+221a -> 0x81e3SQUARE ROOT
    0x8796 -> U+22a5 -> 0x81dbUP TACK
    0x8797 -> U+2220 -> 0x81daANGLE
    0x879a -> U+2235 -> 0x81e6BECAUSE
    0x879b -> U+2229 -> 0x81bfINTERSECTION
    0x879c -> U+222a -> 0x81beUNION
  2. IBM拡張文字のうちJIS X 0208にもある文字はJIS X 0208のほうへ、NEC特殊文字にもある文字はNEC特殊文字のほうへ変換する。
    シフトJISUnicode シフトJIS名称
    0xfa4a -> U+2160 -> 0x8754 ROMAN NUMERAL ONE
    0xfa4b -> U+2161 -> 0x8755 ROMAN NUMERAL TWO
    0xfa4c -> U+2162 -> 0x8756 ROMAN NUMERAL THREE
    0xfa4d -> U+2163 -> 0x8757 ROMAN NUMERAL FOUR
    0xfa4e -> U+2164 -> 0x8758 ROMAN NUMERAL FIVE
    0xfa4f -> U+2165 -> 0x8759 ROMAN NUMERAL SIX
    0xfa50 -> U+2166 -> 0x875a ROMAN NUMERAL SEVEN
    0xfa51 -> U+2167 -> 0x875b ROMAN NUMERAL EIGHT
    0xfa52 -> U+2168 -> 0x875c ROMAN NUMERAL NINE
    0xfa53 -> U+2169 -> 0x875d ROMAN NUMERAL TEN
    0xfa54 -> U+ffe2 -> 0x81ca FULLWIDTH NOT SIGN
    0xfa58 -> U+3231 -> 0x878a PARENTHESIZED IDEOGRAPH STOCK
    0xfa59 -> U+2116 -> 0x8782 NUMERO SIGN
    0xfa5a -> U+2121 -> 0x8784 TELEPHONE SIGN
    0xfa5b -> U+2235 -> 0x81e6 BECAUSE
  3. NEC選定IBM拡張文字は、Unicodeからの変換ではIBM拡張文字のほうへ変換する。ただし、シフトJISで0xeef9は、JIS X 0208にもあるので、JIS X 0208のほうへ変換する。
    0xed40   -> U+7e8a   -> 0xfa5c   CJK Unified Ideograph
    0xed41   -> U+891c   -> 0xfa5d   CJK Unified Ideograph
    0xed42   -> U+9348   -> 0xfa5e   CJK Unified Ideograph
    (中略)
    0xeef8   -> U+2179   -> 0xfa49   Small Roman Numeral Ten
    0xeef9   -> U+ffe2   -> 0x81ca   Fullwidth Not Sign
    0xeefa   -> U+ffe4   -> 0xfa55   Fullwidth Broken Bar
    0xeefb   -> U+ff07   -> 0xfa56   Fullwidth Apostrophe
    0xeefc   -> U+ff02   -> 0xfa57   Fullwidth Quotation Mark
    

別システムの考慮

情報交換のための文字コード(CES)としてUTF-8を使う場合、交換相手の側でEUC-JPからUTF-8に変換し、こちらでUTF-8からEUC-JPに戻す場合がある。交換相手の変換表がこちらと違う場合を考慮すると、できれば、シフトJIS / EUC-JPとUnicodeとの変換表は、多対1にしておきたい。

例えば0x5c -> U+00a5と変換するようなシステムを考慮すると、次の文字を手当てしておくといい。

シフトJIS / EUC-JPUnicodeシフトJIS / EUC-JP
0x5c -> U+005c REVERSE SOLIDUS -> 0x5c
U+00A5 YEN SIGN -> 0x5c
0x7e -> U+007E TILDE -> 0x7e
U+203e OVERLINE -> 0x7e
EUC-JP 0xA1BD-> U+2014 EM DASH-> EUC-JP 0xA1BD
U+2015 HORIZONTAL BAR-> EUC-JP 0xA1BD

使える変換表

上記のテストをパスする変換表であれば、現状では、問題が生じないと思う。

Fedora Core 3 Linux (glibc 2.3.3) でiconv()に与えることができるCES名のうち、妥当なもの、不味いものはそれぞれ次のようになる。

妥当妥当ではない
EUC-JP系 "EUC-JP-MS", "eucJP-MS", "eucJP-open", "eucJP-win" "EUC-JPX0213", "EUC-JP", "eucJP", "ujis"
シフトJIS系 "SJIS-open", "SJIS-win", "CP932", "MS932" "SHIFT-JIS", "Shift_JIS", "Shift_JISX0213", "SJIS", "IBM-932", "IBM932"

iconv()に実装されている変換表がいずれも不味い場合は、別の変換表を使うしかない。Ruby(v1.8.1まで)では、uconvモジュールにパッチを当てて使うのがいい。uconv

Ruby 1.8.2以降では、標準添付のnkfモジュールがEUC-JP/シフトJIS - Unicode変換できるようになっている。変換表もおおむね妥当なもの。(ただし、EUC-JPのみIBM拡張漢字がサポート外。)

外部リンク

[PRB] SHIFT - JIS と Unicode 間の変換問題
Windows(CP932)においてUnicodeと相互変換できない文字の一覧。
コード変換規則
eucJP-openとUCS (Unicode) との間のコード変換規則。
標準情報(TR) TR X 0015:2002 XML日本語プロファイル
シフトJIS / 日本語EUCのバリエーションについて