Edited at

[Java] シフトJISの扱い

More than 3 years have passed since last update.


目的

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つのコードに集約されます。その結果、デコード後にエンコードをすると異なる値になる文字があります。

集約時の優先順位(エンコード時のマッピング)は以下の通りです。


  1. JIS第2水準

  2. NEC特殊文字

  3. 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