目的
Java における SJIS と MS932 の相違点と、扱う際の注意点をまとめます。
- SJIS/MS932 での値を 0xHHHH 形式で表記していますが、1バイト目が上位、2バイト目が下位、つまり big endian (network byte order)です。
いわゆるシフトJIS
いわゆる「シフトJIS」には何種類もありますが、主なものは以下の2つだと思います。
- SJIS (Shift_JIS)
Microsoft が作成したシフトJIS符号化法を、JIS X 0208 に取り込んだもの。
扱える文字集合は当時のJIS漢字(JIS X 0201/0208)の範囲のみ - MS932 (Windows-31J)
Microsoftは、日本語用の文字セットをコードページ932として管理しており、MS-DOS時代には各OEMベンダーでコードページの独自拡張を許可していた。
しかしWindowsを作る際にはコードページの独自拡張を許可せず、それまでに広く使われていたIBMとNECの文字セットを統合して、新たなコードページ932を作成した。
Javaでは、IBMのコードページ932を"CP932"、Microsoftのコードページ932を"MS932"という名前で扱っている。
※Java以外ではMicrosoftのコードページ932のことも"CP932"と呼ぶことが普通だと思うので注意。
参考:
文字集合
SJIS/MS932 では扱える文字集合が異なります。
文字の種類 | SJIS | MS932 | 補足 |
---|---|---|---|
JIS第1水準 | ○ | ○ | |
JIS第2水準 | ○ | ○ | |
NEC特殊文字 | × | ○ | 0x8740~0x879c |
NEC選定IBM拡張文字 | × | ○ | 0xed40~0xeefc |
ユーザ外字 | × | ○ | 0xf040~0xf9fc |
IBM拡張文字 | × | ○ | 0xfa40~0xfc4b |
ちなみに、2バイト文字の範囲は以下のとおりです。
- 1バイト目: 0x81~0x9f, 0xe0~0xef (MS932 は~0xfc)
- 2バイト目: 0x40~0x7e, 0x80~0xfc
NEC特殊文字
NEC選定IBM拡張文字
※Microsoftはこれらの文字を使わないようにと指示しているらしい。同じ文字がIBM拡張文字にあるからだと思われる。
IBM拡張文字
Javaの文字セット名(Charset)
いまさら気にしなくてもよさそうなぐらい古い話ですが、Java におけるCharset名の "Shift_JIS" は途中で意味が変わった(間違えていた)ことがあるらしい。
Javaバージョン | SJISのCharset名 | MS932のCharset名 |
---|---|---|
~ 1.1.7 | SJIS, Shift_JIS | なし |
1.1.8 ~ 1.4.0 | SJIS | MS932, Windows-31J, Shift_JIS |
1.4.1~ | SJIS, Shift_JIS | MS932, Windows-31J |
古い環境でも動作させる必要がある場合には、 "Shift_JIS" は使わないほうが良いかもしれない。
※IANAの正式な登録名は "Shift_JIS" なんですけどね。
SJIS/MS932で異なる文字マッピング
SJISとMS932では、Unicodeコードポイントのマッピングが一部異なります。
具体的には以下の7文字が異なります。
SJIS/MS932 | SJISでデコード | MS932でデコード |
---|---|---|
0x815c | U+2014 : EM DASH "—" | U+2015 : HORIZONTAL BAR "―" |
0x8160 | U+301C : WAVE DASH "〜" | U+FF5E : FULLWIDTH TILDE "~" |
0x8161 | U+2016 : DOUBLE VERTICAL LINE "‖" | U+2225 : PARALLEL TO "∥" |
0x817c | U+2212 : MINUS SIGN "−" | U+FF0D : FULLWIDTH HYPHEN-MINUS "-" |
0x8191 | U+00A2 : CENT SIGN "¢" | U+FFE0 : FULLWIDTH CENT SIGN "¢" |
0x8192 | U+00A3 : POUND SIGN "£" | U+FFE1 : FULLWIDTH POUND SIGN "£" |
0x81ca | U+00AC : NOT SIGN "¬" | U+FFE2 : FULLWIDTH NOT SIGN "¬" |
そのため、SJISとMS932の文字コード変換を混在させると、文字化けすることがあります。
また、Unicodeでは別のコードポイントにマッピングされるので、検索不一致などがおきる可能性があります。
SJIS/MS932 | →SJISでデコード | →MS932でエンコード |
---|---|---|
0x815c | U+2014 : EM DASH "—" | 変換不能 |
0x8160 | U+301C : WAVE DASH "〜" | 変換不能 |
0x8161 | U+2016 : DOUBLE VERTICAL LINE "‖" | 変換不能 |
0x817c | U+2212 : MINUS SIGN "−" | 変換不能 |
0x8191 | U+00A2 : CENT SIGN "¢" | 0x8191 |
0x8192 | U+00A3 : POUND SIGN "£" | 0x8192 |
0x81ca | U+00AC : NOT SIGN "¬" | 0x81ca |
SJIS/MS932 | →MS932でデコード | →SJISでエンコード |
---|---|---|
0x815c | U+2015 : HORIZONTAL BAR "―" | 変換不能 |
0x8160 | U+FF5E : FULLWIDTH TILDE "~" | 変換不能 |
0x8161 | U+2225 : PARALLEL TO "∥" | 変換不能 |
0x817c | U+FF0D : FULLWIDTH HYPHEN-MINUS "-" | 変換不能 |
0x8191 | U+FFE0 : FULLWIDTH CENT SIGN "¢" | 変換不能 |
0x8192 | U+FFE1 : FULLWIDTH POUND SIGN "£" | 変換不能 |
0x81ca | U+FFE2 : FULLWIDTH NOT SIGN "¬" | 変換不能 |
※外部データの読み書きだけではなく、ソースやリソースに記載の文字にも同様の問題がありえることに注意。
MS932の重複文字
MS932 では、同じ文字が複数のコードで表現されていることがあります。
- 「IBM拡張文字」と「NEC選定IBM拡張文字」に同じ字形が存在する。
- 「NEC特殊文字」「NEC選定IBM拡張文字」「IBM拡張文字」と「JIS第2水準」に同じ字形が存在する。
Unicodeのコードポイントは1つしかないため、これらの文字はデコードの際に1つのコードに集約されます。その結果、デコード後にエンコードをすると異なる値になる文字があります。
集約時の優先順位(エンコード時のマッピング)は以下の通りです。
- JIS第2水準
- NEC特殊文字
- IBM拡張文字
いくつか具体例を示します。
文字種類 | "√" | "∵" | "¬" | "№" | "㈱" | "Ⅲ" | "﨑" | "髙" | "ⅲ" |
---|---|---|---|---|---|---|---|---|---|
JIS第2水準 | 0x81e3 | 0x81e6 | 0x81ca | - | - | - | - | - | - |
NEC特殊文字 | 0x8795 | 0x879a | - | 0x8782 | 0x878a | 0x8756 | - | - | - |
NEC選定IBM拡張文字 | - | - | 0xeef9 | - | - | - | 0xed95 | 0xeee0 | 0xeef1 |
IBM拡張文字 | - | 0xfa5b | 0xfa54 | 0xfa59 | 0xfa58 | 0xfa4c | 0xfab1 | 0xfbfc | 0xfa42 |
Unicode | U+221A | U+2235 | U+FFE2 | U+2116 | U+3231 | U+2162 | U+FA11 | U+9AD9 | U+2172 |
エンコード後 | 0x081e3 | 0x81e6 | 0x81ca | 0x8782 | 0x878a | 0x8756 | 0xfab1 | 0xfbfc | 0xfa42 |