Help us understand the problem. What is going on with this article?

[Java] シフトJISの扱い

More than 5 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.png

NEC選定IBM拡張文字

NEC-IBM.png

※Microsoftはこれらの文字を使わないようにと指示しているらしい。同じ文字がIBM拡張文字にあるからだと思われる。

IBM拡張文字

IBM.png

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
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away