文字コードの話 (2) - Shift_JIS

文字コードについて調べたことをまとめます。

関連記事

目次

JIS X 0208

JIS C 0208(旧JIS C 6226)は、1978年に制定された日本語用のコードページ。日本でよく使われる6879字が定義されている。通称「JIS漢字」。
収録されている文字の大部分は漢字であり、漢字は使用頻度によって第1水準・第2水準という分類に分けられている。

文字はという座標位置に保存されている。区は94個あり、それぞれの区の中に94個の点がある。つまり、JIS X 0208は94x94の大きさの文字集合である。
区の内容はそれぞれ以下のようになっている。

内容
1-2区 記号
3区 数字・ラテン文字 (全角英数)
4区 ひらがな
5区 カタカナ
6区 ギリシア文字
7区 キリル文字
8区 罫線記号
9-15区 未割り当て
16-47区 第1水準漢字 (2965字)
48-84区 第2水準漢字 (3390字)
85-94区 未割り当て

例えば「」という文字のコードポイントは「4区2点」で、「」のコードポイントは「16区34点」(0x10区0x22点)である。

JIS X 0208:1990の16区
+0+1+2+3+4+5+6+7+8+9+A+B+C+D+E+F
0x00
0x10
0x20
0x30
0x40
0x50

幽霊文字

JIS X 0208には制定作業時のミスで「典拠不詳」「不明」「同定不能」とされる文字、すなわち存在しない文字が収録されててしまっている。これらの文字は「幽霊文字」と通称され、そのほとんどは誤写と考えられている。
幽霊文字は以下の12文字。

  • 墸 (52区55点)
  • 壥 (52区63点)
  • 妛 (54区12点)
  • 彁 (55区27点)
  • 挧 (57区43点)
  • 暃 (58区83点)
  • 椦 (59区91点)
  • 槞 (60区57点)
  • 蟐 (74区12点)
  • 袮 (74区57点)
  • 閠 (79区64点)
  • 駲 (81区50点)

全角・半角

JIS X 0208はそもそも必ずしもASCIIやJIS X 0201と併用しない想定で作られた規格なので、ASCIIやJIS X 0201で既に定義されているアルファベット・カタカナがJIS X 0208にも独自に定義されている。そのせいで、ASCIIとの互換性のためにASCIIやJIS X 0201とJIS X 0208の両方をエンコードできるように設計された「ISO-2022-JP」・「EUC-JP」・「Shift_JIS」(後述)では、同じ文字に対して2つのバイト表現が存在することとなってしまった。
文字図形を実装するベンダーはこれらの重複文字を同一とは見なさず、2バイトの文字(JIS X 0208)は漢字と同じ幅で、1バイトの文字(JIS X 0201)はその半分の幅で表現する実装を取った(本来、JIS X 0201とJIS X 0208の文字の定義には幅に関する制約がないにもかかわらず)。これがいわゆる「全角」と「半角」である。

このような画面表示上の規格外の慣習は消えることなく残り続け、全角と半角を区別して使った文書は大量に生み出された。そして後にUnicodeが制定されるとき、そのような文書との互換性のため全角と半角が明確に区別されて登録されることとなった。

文字 コードページ ISO-2022-JP EUC-JP Shift_JIS Unicode Unicodeで定義された文字名
A JIS X 0201 0x41 0x41 0x41 0x41 LATIN CAPITAL LETTER A
JIS X 0208 0x23 41 0xA3 C1 0x82 60 0xFF 21 FULLWIDTH LATIN CAPITAL LETTER A
JIS X 0201 (非対応) 0x8E B1 0xB1 0xFF 71 HALFWIDTH KATAKANA LETTER A
JIS X 0208 0x25 22 0xA5 A2 0x83 41 0x30 A2 KATAKANA LETTER A

ISO/IEC 2022

ISO/IEC 2022は、元々はISO/IEC 646に準拠した複数のコードページを切り替えて処理することを目的として1973年に制定されたエンコード方式の規格。その後、同時期に策定中だったJIS X 0208と互いに影響を与えながら改正されて行き現在の形となる。

8bitの場合0x00-0xFFまでの領域全体を、CL(0x00-0x1F)・GL(0x20-0x7F)・CR(0x80-0x9F)・GR(0xA0-0xFF)の4つの領域に分け、GL・GR領域に対応する文字集合を制御文字列によって動的に切り替える(7bitの場合はCR・GR領域がない)。
この仕組みにより、GL・GR領域の複数バイト(オクテット)の組み合わせで一つの文字を表現することができる。

ISO/IEC 2022
0123456789ABCDEF
0CL
1
2GL
3
4
5
6
7
8CR
9
AGR
B
C
D
E
F

ISO-2022-JP

ISO-2022-JPは、1993年に正式に制定されたISO/IEC 2022の7bit実装。通称「JISコード」。
元々JUNETという日本のインターネットの起源となったネットワークにおいて電子メールを通信するために作られた規格。電子メールに関する標準として長い間使われてきたが、現在は使われなくなってきている。

  • 7bitの符号化方式であるため、CR・GR領域は一切使わない。
  • 「ASCII」・「JIS X 0201-1976のラテン文字集合」・「JIS X 0208-1978」・「JIS X 0208」の4つのコードページが利用可能。
  • ESC $ B」(0x1B 0x24 0x42)でGLにJIS X 0208を呼び出し、「ESC ( B」(0x1B 0x28 0x42)でASCIIを呼び出すことができる。
    • ISO-2022-JPの呼び出しは「ロッキングシフト」であり、一度文字集合が呼び出されると別の呼び出しがあるまでその文字集合が維持される。
    • 初期状態ではASCIIが呼び出されているので、ASCII文字から始まる文書の場合は最初の呼び出しは不要。
    • 文書の終わりではASCIIかJIS X 0201-1976のラテン文字集合に戻しておかなければならない。
  • JIS X 0208を呼び出している間は区・点を表す2バイトで文字を表現する。

例えば「通称JISコード」をエンコードする場合を見てみよう。

文字 コードページ コードポイント バイト表現
JIS X 0208 36区44点 0x444C
JIS X 0208 30区46点 0x3E4E
J ASCII 0x4A 0x4A
I ASCII 0x49 0x49
S ASCII 0x53 0x53
JIS X 0208 5区19点 0x2533
JIS X 0208 1区28点 0x213C
JIS X 0208 5区41点 0x2549

JIS X 0208は94x94のコードページなので、コードポイントx区y点に対するバイト表現はx+0x20 y+0x20となる。
途中でコードページが切り替わっているので呼び出し命令を挟み、最後にASCIIに戻すことで最終的なバイト列が完成する。

「通称JISコード」 =
1B 24 42 44 4C 3E 4E 1B 28 42 4A 49 53 1B 24 42
25 33 21 3C 25 49 1B 28 42

EUC-JP

EUC-JPは、UNIXで日本語を扱うために1985年に制定されたISO/IEC 2022の8bit実装

  • GL領域はASCII固定で、GR領域はJIS X 0208がデフォルト。呼び出しによってGR領域を「JIS X 0201-1976の仮名文字集合」や「JIS X 0212-1990」に切り替えることができる。
    • EUC-JPの呼び出しは「シングルシフト」であり、切り替え後の1文字にのみ影響してその後はデフォルト(JIS X 0208)に戻る。
  • 0x8E を先頭に付与することで、「ア」 = 0x8E 0xB1 というように半角カナを呼び出すことができる。
  • 0x8F を先頭に付与することで、「JIS補助漢字」(JIS X 2012)を3バイトで表現することもできる。

例えば「通称JISコード」をエンコードする場合は以下のようになる。

文字 コードページ コードポイント バイト表現
JIS X 0208 36区44点 0xC4CC
JIS X 0208 30区46点 0xBECE
J ASCII 0x4A 0x4A
I ASCII 0x49 0x49
S ASCII 0x53 0x53
JIS X 0208 5区19点 0xA5B3
JIS X 0208 1区28点 0xA1BC
JIS X 0208 5区41点 0xA5C9

EUC-JPではJIS X 0208がGR領域に呼び出されているので、コードポイントx区y点に対するバイト表現はx+0xA0 y+0xA0となる。
この例の場合、文字集合の呼び出しは不要なので単にバイト表現を繋げるだけで最終的なバイト列が完成する。

「通称JISコード」 = C4 CC BE CE 4A 49 53 A5 B3 A1 BC A5 C9

Shift_JIS

切り替え処理が複雑であるというISO/IEC 2022の欠点に対応するため、1982年にMicrosoftら複数の企業が共同でShift_JISというエンコード方式を実装した。後に2004年のJIS X 0213の改訂により公的な規格となる。

Shift_JISではASCII文字や半角カナはJIS X 0201同様に1バイトで表現し、2バイト文字は1バイト目0x81-0x9F, 0xE0-0xEFと2バイト目0x40-0xFCの組み合わせで表現する。
以下に概略図を示す。

第1バイト
0123456789ABCDEF
0 
1
2 !"#$%&'()*+,-./
30123456789:;<=>?
4@ABCDEFGHIJKLMNO
5PQRSTUVWXYZ[\]^_
6`abcdefghijklmno
7pqrstuvwxyz{|}~
81357911131517192123252729
931333537394143454749515355575961
A
Bソ
C
D
E63656769717375777981838587899193
F
第2バイト
0123456789ABCDEF
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
  • 第1バイトの0x81-0x9F, 0xE0-0xEFの部分に書いてある数字は対応するJIS X 0208の区番号である。第2バイトには2つの区を配置できるので、例えば第1バイトが0x8Eの場合(27と表記されている部分)は27区と28区に対応していることを表している。
  • 第2バイトの2つの色で分けられている部分はそれぞれ奇数区と偶数区の配置箇所である。例えば0x8Eの場合、緑の部分が27区で青の部分が28区となる。
  • 9-15区, 85-94区はJIS X 0208において未割り当ての領域である。
  • Shift_JISの「Shift」とは、第2バイトの図のようにJIS X 0201の文字集合をずらして配置していることを意味しているらしい。
  • 「SJIS」などと表記されることもある。

例えば「あ」(4区2点)の場合、第1バイトは0x82、第2バイトは0xA0となる。

第1バイトが0x82のときの第2バイト
0123456789ABCDEF
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F

CP932

MicrosoftはMS-DOSの標準日本語コードにShift_JISを採用し、「CP932」と名付けた。
CP932には上記のように未割り当ての区第1バイトの未使用の領域があったため、Microsoftはそれらの領域を日本向けにパソコンを製造するメーカーが自由に拡張しても良い部分と定めた。その結果、次のようにIBMとNECがそれぞれ独自に文字を追加することとなり、CP932は多様化し始めることとなる。

IBMの拡張

IBMは第1バイトのFの段を利用して文字の拡張を行った。

  • 0xF0-0xFFを95区-126区と見立てて115区-119区に「髙」「﨑」「彅」などの388字を追加した。(IBM拡張文字)
第1バイト
0123456789ABCDEF
0-7ASCII
81357911131517192123252729
931333537394143454749515355575961
A
Bソ
C
D
E63656769717375777981838587899193
F959799101103105107109111113115117119121123125

NECの拡張

IBMは未割り当ての区を利用して文字の拡張を行った。

  • 9-13区に特殊文字を追加した。
    特に13区に追加された「①」「Ⅰ」「㍉」「㍻」などの83字は後の統合において「NEC特殊文字」と呼ばれることとなる。
  • IBMが追加した388字の内、漢字374字をそのまま89-92区に追加した。(NEC選定IBM拡張文字)
第1バイト
0123456789ABCDEF
0-7ASCII
81357911131517192123252729
931333537394143454749515355575961
A
Bソ
C
D
E63656769717375777981838587899193
F959799101103105107109111113115117119121123125

Windows-31J

Windows-31Jは1993年にMicrosoftがWindows 3.1の日本語版を発売する際に、上記のように多様化していたCP932の実装を統一した規格。
上記の「IBM拡張文字」・「NEC特殊文字」・「NEC選定IBM拡張文字」をそのまま同じ位置に継承した。

第1バイト
0123456789ABCDEF
0-7ASCII
81357911131517192123252729
931333537394143454749515355575961
A
Bソ
C
D
E63656769717375777981838587899193
F959799101103105107109111113115117119121123125

WindowsでShift_JISを扱うときは、意識せずに実際にはこのWindows-31Jを扱っている場合があることに注意が必要である。混同を防ぐためにJavaでは「MS932」とも呼ばれる。
日本のWindowsでは「ANSI」という言葉がWindows-31Jを指す場合がある。(ANSIは利用環境における標準規格を指しているらしい)
現在ではOS内部でもUnicode(UTF-16)が使われるようになり、Shift_JISは廃れつつある。

文字の重複

NEC選定IBM拡張文字は全てIBM拡張文字に含まれるので、Windows-31Jには文字の重複登録が大量にある。
また、それ以外にもそもそもIBM拡張文字とNEC特殊文字に重複があったり、JIS X 0208側に文字が追加されたことで重複したりということが起きている。

  • 「髙」 = 0xEEE0(92区) = 0xFBFC(118区)
  • 「㈱」 = 0x878A(13区) = 0xFA58(115区)
  • 「∵」 = 0x81E6(2区) = 0x879A(13区) = 0xFA5B(115区)
    (JIS X 0208-1983で2区に追加された)

ブラウザーで見る (ダウンロードしてバイナリーエディターで開くとエンコードの違いが見られる)

参考

Shift_JIS