rohaniのブログ

ゆるっと自然言語処理奴。ときどき工作系バイト。

授業で文字コード(JIS, Shift-JIS, EUC)の話を聞いたけど、さっぱりイメージできなかったので実際に見てみた

テキストファイルをバイナリでみる方法

hexdump というUNIXコマンドを使うと16進数でみることができる。
また、 nkf というUNIXコマンドを使うと文字コードを変換できる。
これらを使って、任意のテキストファイルの内容を「普通に」「JISコードで符号化して」「Shift-JISコードで符号化して」「EUCコードで符号化して」見てみるスクリプトを書いた。

<< DEFINE
任意のファイルの文字コードを指定してバイナリで閲覧するファイル
fname; サンプルテキストファイル
chara; 見たい文字コードのnkf指定パラメータ
DEFINE
fname='test.txt'
echo $fname
cat $fname  # 普通に

chara='-j'
echo $chara
nkf $chara $fname | hexdump  # JISで符号化して

chara='-s'
echo $chara
nkf $chara $fname | hexdump  # Shift-JISで符号化して

chara='-e'
echo $chara
nkf $chara $fname | hexdump  # EUCで符号化して

出力結果を見てみる

test.txt
aAアあ阿啞
aアaあa阿a啞a
-j
0000000 61 41 1b 24 42 25 22 24 22 30 24 1b 28 42 0a 61
0000010 1b 24 42 25 22 1b 28 42 61 1b 24 42 24 22 1b 28
0000020 42 61 1b 24 42 30 24 1b 28 42 61 61 0a         
000002d
-s
0000000 61 41 83 41 82 a0 88 a2 0a 61 83 41 61 82 a0 61
0000010 88 a2 61 61 0a                                 
0000015
-e
0000000 61 41 a5 a2 a4 a2 b0 a4 0a 61 a5 a2 61 a4 a2 61
0000010 b0 a4 61 61 0a                                 
0000015

test.txtの中身が大量のアで埋め尽くされているのはバグではない.仕様.
さて,JISから順番に見ていく.

JIS

JISの符号空間をざっくり書くと以下のようになる. Shift-JISやEUCと違ってエスケープシーケンスを必要とする.

  • 0x00~0x1f:制御コード
  • 0x20~0x7e:ASCIIコード "ESC ( B"→1B 28 42:ASCII開始
    • 0x21~0x7e:上位1バイト、下位1バイト "ESC $ B"→1B 24 42:新JIS漢字開始
    • 0x21~0x5f:7ビットの半角カナ "ESC ( I"→1B 28 49:半角カナ開始
  • 0x7f:制御コード
  • 0xa1~0xdf:8ビットの半角カナ

参考:文字コード表 JISコード(ISO-2022-JP)

61(a:ASCII) 41(A:ASCII) 1b 24 42(漢字開始) 25 22(ア→ア:全角文字!?) 24 22(あ:全角文字) 30 24(阿:全角文字) 1b 28 42(ASCII開始) 0a(LF:制御コード)

aAは共に1バイトコードで,ASCIIの領域.
続いて、本来ならば半カナ開始の"ESC ( I"が来るところだが、aAに続くアは半カナではなく全カナのアで符号化されているので、漢字開始の"ESC $ B"が来ている。
半角カナではなく全角カナで符号化されているのは多分nkfの変換誤りではないかなと思っている.
アに続くあ阿は共に2バイトコードで,JISの符号空間で符号化されている.
そして,その次に来るはずの啞が抜けている.JISの文字集合に啞は含まれているはずなのだが、どういうことだろう?と思ったが、nkf --help によると nkf -jISO-2022-JP に変換するコマンドらしい。JISと呼ばれる符号空間は実は複数あって、ネットで単純にJISと検索するとそれらが無差別にヒットする。 ISO-2022-JP文字集合一覧を見ると、確かに、啞は含まれていなさそうだった。
啞の後には,テキスト表示はされていないが改行コードが入っているので,それも符号化されている.

61(a:ASCII) 1b 24 42(漢字開始) 25 22(ア→ア:全角文字!?) 1b 28 42(ASCII開始) 61(a:ASCII) 1b 24 42(漢字開始) 24 22(あ:全角文字) 1b 28 42(ASCII開始) 61(a:ASCII) 1b 24 42(漢字開始) 30 24(阿:全角文字) 1b 28 42(ASCII開始) 61(a:ASCII) 61(a:ASCII) 0a(LF:制御コード)

改行後には、aで区切られた様々なアが続く。 全種類のコード切り替えを試したかった部分なのだが、半カナが全カナになってしまっているので半カナ開始コードの確認はできなかった。
JISコードはASCII/漢字/半カナ切り替えがあると凄く長くなってしまう様子が確認できる。

Shift-JIS

Shift-JISの符号空間をざっくり書くと以下のようになる. JISと違ってエスケープシーケンスはなく,EUCと違って2バイトコードと1バイトコードの領域が重なっている.

  • 0x00~0x1f,:制御コード
  • 0x20~0x7e:ASCII  0x40~0x7e:全角文字下位1バイト
  • 0x7f:制御コード
  • 0x80~0xfc:全角文字下位1バイト
    • 0x81~0x9f:全角文字上位1バイト
    • 0xa1~0xdf:半カナ
    • 0xe0~0xef:全角文字上位1バイト

参考:文字コード表 シフトJIS(Shift_JIS)

61(a:ASCII) 41(A:ASCII) 83 41(ア→ア:全角文字!?) 82 a0(あ:全角文字) 88 a2(阿:全角文字) 0a(LF:制御コード)

Shift-JISの符号空間で符号化されているのが確認できる。
今回もアは半カナではなく全カナのアで符号化されている。多分nkfの変換誤り。 そしてやはり啞が抜けている.色々なサイトに掲載されている表を確認した感じ,どうやらShift-JISの文字集合には啞が存在しないらしいがShift-JISよお前もか.

61(a:ASCII) 83 41(ア→ア:全角文字!?) 61(a:ASCII) 82 a0(あ:全角文字) 61(a:ASCII) 88 a2(阿:全角文字) 61(a:ASCII) 61(a:ASCII) 0a(LF:制御コード)

相変わらずアが全角のアに変わっているのと,啞が抜けていること以外はShift-JISで符号化されている様子が確認できる. エスケープシーケンスが無いので,ASCII/全角文字コードへの切り替えもすっきり.

EUC

日本語EUCの符号空間をざっくり書くと以下のようになる. JISと違ってエスケープシーケンスはなく,Shift-JISと違って多バイトコードと1バイトコードの領域が重なっていない.
そして、JIS、Shift-JISと違って3バイトコードがある。

  • 0x00~0x1f,:制御コード
  • 0x20~0x7e:ASCII
  • 0x7f:制御コード
  • 0x8e:半角カナ上位1バイト
  • 0x8f:3バイトコードの上位1バイト
  • 0xa0~0xfe:2バイトコードの上位下位1バイト、3バイトコードの下位2バイト
    • 0xa1~0xdf:半角カナ下位1バイト

参考:文字コード表 日本語EUC(euc-jp)

61(a:ASCII) 41(A:ASCII) a5 a2(ア→ア:全角文字!?) a4 a2(あ:全角文字) b0 a4(阿:全角文字) 0a(LF:制御コード)

EUCの符号空間で符号化されているのが確認できる。
今回もアは半カナではなく全カナのアで符号化されている。多分nkfのへんk (ry。
そして、何故か、啞が抜けている.今度こそ不思議。EUC-JPの文字集合には啞は入っているはず。3バイトコードを確認しようと思って入れたのだから。えぇーなんでー。

61(a:ASCII) a5 a2(ア→ア:全角文字!?) 61(a:ASCII) a4 a2(あ:全角文字) 61(a:ASCII) b0 a4(阿:全角文字) 61(a:ASCII) 61(a:ASCII) 0a(LF:制御コード)

アが全角のアに変わっているのと,啞が抜けていること以外はEUCで符号化されている様子が確認できる. Shift-JIS同様 エスケープシーケンスが無いので,ASCII/全角文字コードへの切り替えもすっきり.

感想

  • JIS、Shift-JIS、EUCの符号表現を見てみた。
  • JISのエスケープシーケンスによる切り替えや、Shift-JISの2バイトコードの下位の一部がASCIIの領域と被っていることなどが確認できた。
  • 副次的効果として、nkfによってアと啞がうまく変換されていないかもしれないことが発見できた。

半角カナ開始エスケープシーケンスと、EUCの3バイト符号化を確認できなかったことが心残りだけど、 以前よりはイメージが掴めたかなと思う。

勉強おつかーれさんです。 f:id:ojho0318:20180604222013p:plain
鳥獣戯画の蛙さん