シフト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. [MUST] 0x20〜0x7E のそれぞれの文字について、U+0020〜U+007E (Basic Latin; ISO/IEC 646 IRV) に相互に変換できること。これ以外の文字がU+0020〜U+007Eに変換されないこと。

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

    シフトJIS / EUC-JPUnicode (誤り)Unicode (妥当)
    0x5C U+00A5 YEN SIGN U+005C REVERSE SOLIDUS
    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. [MUST] ISO/IEC 646 IRV、JIS X 0201カタカナ、JIS X 0208漢字集合に含まれる文字をすべてUnicodeの別のコードポイントに変換し、かつシフトJIS、EUC-JPに戻したときにすべて元のコードポイントに戻ること。(round-trip conversion)

    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補助漢字

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

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

NEC特殊文字にはJIS X 0208に含まれる文字があり (多重符号化)、また, NEC選定IBM拡張文字も, IBM拡張文字から記号と漢字を選んでいるので, 完全に被っている。

IBM拡張文字(388文字)
NEC選定IBM拡張文字(374文字) NEC特殊文字 (83文字)
373文字

ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹ¦'"
纊褜鍈銈蓜俉炻昱棈鋹曻彅丨仡仼伀伃伹佖侒侊侚侔俍偀倢俿倞偆偰偂傔僴僘兊兤冝冾凬刕劜劦勀勛匀匇匤卲厓厲叝﨎咜咊咩哿喆坙坥垬埈埇﨏塚增墲夋奓奛奝奣妤妺孖寀甯寘寬尞岦岺峵崧嵓﨑嵂嵭嶸嶹巐弡弴彧德忞恝悅悊惞惕愠惲愑愷愰憘戓抦揵摠撝擎敎昀昕昻昉昮昞昤晥晗晙晴晳暙暠暲暿曺朎朗杦枻桒柀栁桄棏﨓楨﨔榘槢樰橫橆橳橾櫢櫤毖氿汜沆汯泚洄涇浯涖涬淏淸淲淼渹湜渧渼溿澈澵濵瀅瀇瀨炅炫焏焄煜煆煇凞燁燾犱犾猤猪獷玽珉珖珣珒琇珵琦琪琩琮瑢璉璟甁畯皂皜皞皛皦益睆劯砡硎硤硺礰礼神祥禔福禛竑竧靖竫箞精絈絜綷綠緖繒罇羡羽茁荢荿菇菶葈蒴蕓蕙蕫﨟薰蘒﨡蠇裵訒訷詹誧誾諟諸諶譓譿賰賴贒赶﨣軏﨤逸遧郞都鄕鄧釚釗釞釭釮釤釥鈆鈐鈊鈺鉀鈼鉎鉙鉑鈹鉧銧鉷鉸鋧鋗鋙鋐﨧鋕鋠鋓錥錡鋻﨨錞鋿錝錂鍰鍗鎤鏆鏞鏸鐱鑅鑈閒隆﨩隝隯霳霻靃靍靏靑靕顗顥飯飼餧館馞驎髙髜魵魲鮏鮱鮻鰀鵰鵫鶴鸙黑

13文字

ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ№℡㈱

61文字

①②③④⑤⑥⑦⑧⑨⑩ ⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ ㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗ ㌍㌦㌣㌫㍊㌻㎜㎝㎞㎎ ㎏㏄㎡㍻〝〟㏍㊤㊥㊦ ㊧㊨㈲㈹㍾㍽㍼∮∑∟ ⊿

1文字
1文字
8文字
≒≡∫√⊥∠∩∪
6869文字
(省略)
JIS X 0208:1990(6879文字)
出典 https://ja.wikipedia.org/wiki/Microsoftコードページ932

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

Unicode からの変換では, 次のように寄せたほうがいい。

  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にもある文字 (2字) は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, UTF-16を使う場合、交換相手の側でEUC-JPからUTF-8/16に変換し、こちらで 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, SJIS 0x815c

使える変換表

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

結論としては、「シフトJIS」については「マイクロソフト標準キャラクタセット」 (Windows-31J, MS932) がよい。歴史的に "cp932" は, IBMのコードページの場合があるので、注意が必要。

EUC-JPについては eucJP-open がよいが、これは変換表ではない。eucJP-ms, eucJP-0201 または eucJP-ascii のうちどれか、となっている。 eucJP-0201 は妥当ではないので、明示的に eucJP-mseucJP-ascii を指定すべき、となる。

Unicode とユーザ定義文字・ベンダ定義文字に関する問題点と解決策 TOG/JVC CDE/Motif 技術検討 WG.

glibc iconv

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

(2019.7) Fedora 30 Linux (glibc 2.29) で更新.

妥当妥当ではない
EUC-JP系 "EUC-JP-MS", "eucJP-MS", "eucJP-win" CSEUCPKDFMTJAPANESE, EUC-JISX0213, EUC-JP, eucJP, ujis - NEC特殊文字の一部をサポートしない。

eucJP-open - 変換表を特定できず、使うべきでない.

シフトJIS系 "SJIS-open", "SJIS-win", "CP932" *1, "MS932", Windows-31J, CSWINDOWS31J CSSHIFTJIS, SHIFT-JIS, Shift_JIS, ShiftJISX0213, SHIFT_JISX0213, SJIS - IRVが不正

IBM-932, IBM932 - NEC特殊文字をサポートしない.

"Shift_JIS" のようなシフトJISっぽい名前のほうが不味い表になっていることに注意しよう。

SJIS-win, eucJP-win は PHP 由来か? 合意された定義か怪しい。

SJIS-open は、上述の eucJP-open との対比で定められたもの。マイクロソフト標準キャラクタセット (Windows-31J, MS932) と同じ。

Ruby

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

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

ICU

(2019.7) UnicodeライブラリのデファクトスタンダードであるICUで、妥当な変換表を得るには、次の名前を与えること。

妥当 妥当ではない
シフトJIS系 ibm-943_P15A-2003, windows-31j, csWindows31J, ms932, CSSHIFTJIS, SJIS - 全部同じ変換表。 IBM-932 - 1999版. 収録文字が少ない.

SHIFT_JIS, CP932 - 1999版と名称が曖昧

EUC-JP系 CSEUCPKDFMTJAPANESE, EUC-JP, EUCJP, UJIS - IBM拡張文字が89区から92区 (0xF9 - 0xFC; NEC選定IBM拡張文字の位置) が優先されるが、ほかは妥当。 ibm-954, ibm-33722_VPUA - NEC特殊文字が全滅. JIS X 0208記号も足らない.

ibm-33722_P120-1999 - '\' => yen sign. NG

glibc と変換表が異なる。

Java

JIS-Unicode間の変換表の選択について

波ダッシュ WAVE DASH問題

(2019.7) シフトJIS "ms932" で、チルダ、波ダッシュの変換が怪しい。

シフトJIS -> Unicode -> シフトJIS
0x7e U+007E TILDE 0x7e
0x8160 U+FF5E FULLWIDTH TILDE 0x8160
-- U+301C WAVE DASH n/a (変換先なし)

JIS X 0212補助漢字にはチルドがある。

eucJP-ascii

a1 c1 => U+301C WAVE DASH
8F A2 B7 => U+FF5E

eucJP-ms

a1 c1 => U+FF5E FULLWIDTH TILDE
8F A2 B7 => U+FF5E

eucJP-ms のほうは、両方を U+FF5E にマッピングしてしまっている。

外部リンク

標準情報(TR) TR X 0015:2002 XML日本語プロファイル
シフトJIS / 日本語EUCのバリエーションについて