TSG 部報 第 199 号・新入生歓迎号


文字コードの話

早坂くりす

はじめに

 ASCIIだけで用が足りるアメリカと違って、私たちは日本語を扱わなくてはならないため、より深く文字コードの問題と関わらざるをえません。それでも、MS-DOS/WindowsやMacを使う限りでは、ASCIIとシフトJIS(たまにJIS)を知っていれば済みますが、UNIXやインターネットを使い始めると、JIS・EUC・シフトJISとさまざまな日本語コードに頭を悩ませることになります。さらに最近はUnicodeも登場し、Windows95/NTの内部コードとして実際に使われ始めています。
 その他にも、文字コードに関してはいろいろ疑問があることと思います。

こういった問題に対処するには、文字コードに関する体系的な理解が必要となります。
 なお、この連載では、とっつきにくさを避けるため、最初のうちは未定義の用語や必ずしも厳密でない説明を用いることがありますので、正しい理解のためには必ず最後まで読んでください。(^_^)

第1章 日本語のコード体系

 この章では、もっとも身近な日本語のコード体系について概観します。
 昔(1970年代まで)は各メーカーごとにさまざまなコード体系が使われていましたが、1978年にJIS漢字が制定されてからは、これに基づいたコード体系が完全に主流となりました。

1.1 JISコード

 インターネットで日本語のメールやネットニュースに使われているコード体系です。

制御コード 0x00〜0x1F、0x7F
ASCII文字 0x20〜0x7E
カタカナ 0x21〜0x5F (7ビット) / 0xA1〜0xDF (8ビット)
漢字 0x2121〜0x7E7E
(第1バイト・第2バイトとも0x21〜0x7E)
補助漢字 0x2121〜0x7E7E
(第1バイト・第2バイトとも0x21〜0x7E)

 ASCIIとカタカナを基本とし、漢字が追加されています。ASCIIと漢字のコード範囲が重複するため、以下のようなエスケープシーケンスによって切り替えます。

漢字の開始 ESC $ @ または ESC $ B
ASCIIの開始 ESC ( B または ESC ( J

補助漢字を含めることも可能であり、補助漢字の開始のシーケンスは ESC $ ( D となります。
 また、7ビットの環境では、カタカナもこれらと重複するため、制御コードまたはエスケープシーケンスで切り替えます。
カタカナの開始 SO (0x0E) または ESC ( I
ASCIIの開始 SI (0x0F) または ESC ( B または ESC ( J

このようにカタカナも7ビットで表現するものを俗に7ビットJISと呼び、これに対してカタカナを8ビットで表現するものを俗に8ビットJISと呼びます。
 JISコードの利点の一つは、7ビットの通信路でも伝送できることです。未だに7ビットの伝送路が少なくないインターネットの世界で使われている理由もここにあります。しかし、エスケープシーケンスの存在が厄介ですので、コンピュータ内部のデータ処理ではあまり使われません。
 なお、98のN88日本語BASICや、PC-PR系プリンタなどでも同様のコードが使われていますが、エスケープシーケンスが "ESC K" と "ESC H" という独自のものになっています。これは通称NEC JISと呼びます。

1.2 シフトJIS(MS漢字コード)

 パソコンでおなじみのコード体系です。一部のUNIX(NEWS-OS、HP-UXなど)でも採用されています。その起源は、日本最初の16ビットパソコンである三菱Multi16にさかのぼります。Multi16にCP/M-86の日本語対応版を搭載するにあたって、処理の容易なコードとしてマイクロソフトなど数社が策定したのがシフトJISです。

制御コード 0x00〜0x1F、0x7F
ASCII文字 0x20〜0x7E
カタカナ 0xA1〜0xDF
漢字 0x8140〜0x9FFC、0xE040〜0xFCFC
(第1バイト: 0x81〜0x9F、0xE0〜0xFC
第2バイト: 0x40〜0x7E、0x80〜0xFC)

 8ビットパソコンで広く使われていたASCIIとカタカナをそのまま継承し、なおかつJISコードのようなエスケープシーケンスを使わずに漢字を混在させるために、所定の計算式によってJIS漢字コードを変換しています。
 漢字の第1バイトはASCIIやカタカナと重複しないように配置されており、第1バイトを見ただけで文字種がわかるようになっています。漢字の第2バイトについても、区切り文字として使われることの多いASCIIの0x20〜0x3Fや、制御コードである0x7Fと重複しないようになっています。また、画面上ではASCIIやカタカナと漢字の幅の比率は1:2であることが多いですが、文字コードのバイト数もこれと同じく1:2になっています。このような特長のため、特別にシフトJISに対応していないシステム上でもなんとか日本語を通せる場合が少なくありません。
 欠点としては、コード空間に余裕が少なく拡張性に乏しい(例えば、補助漢字を入れるスペースがない)こと、第2バイトに含まれる0x40〜0x7Eのコード(特に、ASCIIのバックスラッシュにあたる0x5C)が問題となる場合があること、MSBが落ちたときの復元が困難なこと、などがあげられます。

1.3 日本語EUC

 UNIXの日本語環境でよく使われるコード体系です。EUCはExtended UNIX Codeの略で、UNIXの多言語対応の一環として制定されました。EUCには日本語EUCの他に中国語EUC、韓国語EUCなどもあります。日本語EUCのことをUJIS (Unixized JIS)とも呼びます。

制御コード 0x00〜0x1F、0x7F
ASCII文字 0x20〜0x7E
漢字 0xA1A1〜0xFEFE
(第1バイト・第2バイトとも0xA1〜0xFE)
カタカナ 0x8EA1〜0x8EDF
補助漢字 0x8FA1A1〜0x8FFEFE
(第2バイト・第3バイトとも0xA1〜0xFE)

 JISやシフトJISとの大きな相違点は、カタカナが冷遇されていることです。JIS漢字コードの各バイトのMSBを1にすることにより漢字を導入したため、これと重複するカタカナは補助的な扱いとなり、0x8Eのプレフィクス付きの2バイトコードになっています。また、0x8Fのプレフィクスにより補助漢字も表現でき、これは3バイトになります。
 特長としては、エスケープシーケンスがない、第1バイトを見ただけで文字種がわかる、漢字の第2バイトがASCIIと重複しない、ASCIIと漢字のバイト数の比率が文字の幅と一致する、などシフトJISと類似した点に加えて、JISとのコード変換が容易なことがあげられます。
 ただし、バイト数はカタカナや補助漢字まで考慮すると複雑となります。事実、EUCを採用したシステムでも、補助漢字までサポートしている例は非常に少なく、カタカナのサポートもつい最近まではなおざりにされてきました。日本のインターネット上では、今に至るまでカタカナの使用がタブーとされていますが、これは、EUCを採用しながらカタカナをサポートしていないシステムが多かったためでもあります。
 他の欠点としては、シフトJISよりマシとはいえ拡張性に限界があること、結果的にシフトJISと似て非なるものとなってしまい日本語コードの混乱を助長してしまったこと、などです。

第2章 ASCIIと1バイト文字コード

 この章は、ASCIIと、それをベースにした1バイト文字コードについて、詳しく見ていきます。

2.1 ASCII(American Standard Code for Information Interchange)

 おなじみASCIIは7ビットの文字コードであり、その構成は次のようになっています。

0x00〜0x1F 制御文字(control characters)
0x20 空白(SP)
0x21〜0x7E 図形文字(graphic characters)
0x7F 制御文字DEL(delete)

 制御文字とはいわゆるコントロールコードのことです。図形文字というと●とか▲とかハートマークとか罫線とかを思い浮かべるかもしれませんが、そうではなくて、アルファベット・数字・記号などの「目に見える形をもった」普通の文字のことです。空白は制御文字とも図形文字ともみなすことができます。個々の制御文字や図形文字の詳細については割愛しますが、図形文字で特に注意を要するのは次のコードです。

0x5C バックスラッシュ「\」 (≠円記号)
0x7C 縦棒「|」 (≠破線)
0x7E チルダ「〜」 (≠オーバーライン)

 ASCIIはあくまで7ビットですので、0x80〜0xFFは含まれません。パソコンのマニュアルなどを見ると、0x80〜0xFFにカタカナやら何やらが入ったものを「ASCIIコード表」と称していることが多いですが、これはまちがいです。
 余談ですが、制御文字の中でDELだけ0x7Fなんていうところに飛ばされているのはなぜでしょうか? これは、データ入力媒体として紙テープを使っていたころの名残だといわれています。紙テープでは、所定の位置に穴を空けてあるかどうかによって2進数の1/0を区別します(SunOSのppt(6)を参照)。1文字は7ビットですから、7つの位置の穴の有無で1文字を表します。で、もし穴を空けるときにまちがってしまった場合、穴をふさぐのは面倒ですので、そのまちがいを含む7ビット分全部の穴を空けて「この字はまちがいだから削除ね」ということにしていました。つまり、「削除」→「全ビット1」→「0x7F」というわけです。

2.2 ISO 646

 ISO(International Standardization Organization、国際標準化機構)では、国際的な工業規格を策定しています。コンピュータに関係のある標準化団体はいくつかありますが、ISOはその代表的なものの一つです。フロッピーディスク、CD-ROM、MOディスクなどもISOの規格になっており、機種を超えて互換を保てるようになっています。

 文字コードに関してもISO規格は中心的役割を担っています。まずはISO 646という規格の登場です。これは、もともとアメリカ/英語用の規格であるASCIIを、他の国/言語用に一部変更できるようにしたものです。サンプルとしてIRV(International Reference Version)というものを用意しておき、これを各国が自国の規格として採用するとき、その中の一部のコードに関しては違う文字を割り当ててもよい、というふうになっています。実際にはIRVはASCIIと同じものです(数年前までは違っていた)。
 IRVのうち、文字の割り当てを変更することが認められているコードは次の12個です。参考として、IRV(ASCII)で割り当てられている文字を併記します。

0x23 #   0x5C \   0x7B {  
0x24 $   0x5D ]   0x7C |  
0x40 @   0x5E ^   0x7D }  
0x5B [   0x60 `   0x7E 〜  

 ISO 646のアメリカ版すなわちASCIIでは、これらの文字はそのままですが、ISO 646の各国版を見てみると、これらのコードに割り当てられている文字がそれぞれ違っています。例えば、ヨーロッパの多くの言語では、アクセント記号付きの文字が必要なので、それらをここに割り当てています。また、これだけでは足りない場合は、制御文字BS(backspace)を使い、合成文字として表現することを認めています。例えば、aに^を付けたものを表現する場合は、^ BS a となります。
 ISO 646の日本版は、IRVの0x5Cを円記号に、0x7Eをオーバーラインにしたものです。これはJIS X 0201というJIS規格になっており、JISローマ文字集合(JIS Roman)と呼ばれています。国産のコンピュータはたいていこれを採用しているため、0x5Cが円記号に、0x7Eがオーバーラインになっているというわけです。ただし、NECのPCシリーズとその互換機に関しては、0x7EはIRVと同じチルダになっており、0x7CはIRVともJIS X 0201とも違う「破線」になっています。この結果、PCシリーズの0x21〜0x7Eの図形文字集合は、ISO 646のどの版とも一致しない独自のものになっています(ついでに言うと、古いマシンでは0x60が空白になっている)。
 ところで、シリアルプリンタを持っている人は、マニュアルのディップスイッチの項を見てください。「各国文字の選択」という設定で、日本・アメリカ・イギリス・ドイツ・スウェーデンなどの選択肢があると思います。これはまさしくISO 646の各国版を切り替えていることに他なりません。

 ISO 646のこのような仕組みは、コンピュータのメモリや通信路が限られていた時代に、7ビットという狭いコード空間でなんとかやりくりするためのものだったわけですが、当然の結果として、同じコードでも各国版によって表現する文字が違ってしまうという問題があります。JIS X 0201におけるバックスラッシュと円記号の違いはみなさんもご存じの通りです。
 しかし、日本ではその程度ですからまだ我慢できますが、上記のコードにアクセント記号付きアルファベットなどを割り当ててしまった国ではそれどころではありません。特にCやUNIXでは上記の記号を多用しますが、これらがすべて「u-ウムラウト」やら「e-アクサンテギュ」やらになってしまっているのです。これではとてもCやUNIXを使ってはいられません(この問題に熱心なのはデンマークで、これらの記号を使わずにCを記述するための代用記法トライグラフを提唱しています)。
 最近は、ASCIIをもとにしたISO 8859-1(後述)などの8ビットコードを使えるシステムが一般化したため、7ビットでしかも一国でしか通用しないISO 646各国版にこだわる必要もなくなってきました。そのため、ISO 646各国版は(日本を除いて)流行らなくなりつつあり、ASCIIをそのまま使うケースが多くなっています。

2.3 8ビットコード

 ラテンアルファベットを使うヨーロッパ諸語(英独仏など)は、ISO 646でもなんとか表現できます。しかし、ロシア語・ギリシア語・日本語などの、文字体系が全く異なる言語は表現できません。かといって、アメリカ/英語/ASCIIがコンピュータ界を支配している現状を考えると、ISO 646を排除して独自のコードを使うのは現実的ではありません。したがって、ISO 646(またはASCII)を8ビットに拡張し、0x80〜0xFFに文字を追加しようという考えが生まれます。
 その一つが、これもおなじみJISカタカナです。前述のJIS X 0201では、ISO 646の日本版を定めると共に、これを8ビットに拡張し、0xA1〜0xDFにカタカナを入れました。つまり、JIS X 0201の左半分(0x00〜0x7F)はISO 646日本版で、右半分(0x80〜0xFF)は日本独自規格のカタカナというわけです。当時はまだコンピュータで漢字を扱うのが容易でなかったため、この規格は広く受け入れられました。

 一方、欧米のコンピュータでも、ASCIIを8ビットに拡張して、そこにアクセント記号付きアルファベットや罫線を入れるようになりました。
 パソコンの世界では、IBM PCの普及にともなってPCのコードが有力になりました。DOSのマニュアルにあるコードページ437、WindowsにおけるOEMコードセットというコードです。これの右半分には、アクセント記号つきラテンアルファベット・罫線・各種記号が入っています。しかし、言語によってはこれでも不十分なので、EGAやVGAでは右半分がPCG(死語:-))になっており、ここのフォントを入れ換えることができるようになっています。こうして、IBM PCのコードにはコードページと呼ばれるいくつもの変種ができました。これらもDOSのマニュアルに載っています。なお、MacintoshはIBM PCとはまた違った拡張コードを持っています。

コードページ 名称(言語) 文字種
437 IBM PC基本 ラテン文字
850 多言語(西欧諸語) ラテン文字
852 スラブ(東欧)語 ラテン文字
857 トルコ語 ラテン文字
860 ポルトガル語 ラテン文字
861 アイスランド語 ラテン文字
863 カナダフランス語 ラテン文字
865 北欧語 ラテン文字
869 ギリシア語 ギリシア文字
932 日本語 カタカナ(JIS X 0201)

 また、ISOでもASCIIをベースとした8ビットコードの規格をいくつか制定しました。その中でも有力なものが、ISO 8859という規格です。これもIBM PC同様、ASCIIを左半分に持ついくつもの変種(現在10個)からなっています。

ISO 8859-1 (Latin-1) ラテン文字 西欧諸語
ISO 8859-2 (Latin-2) ラテン文字 東欧諸語
ISO 8859-3 (Latin-3) ラテン文字 エスペラントなど
ISO 8859-4 (Latin-4) ラテン文字
ISO 8859-5 キリル文字 ロシア語など
ISO 8859-6 アラビア文字 アラビア語
ISO 8859-7 ギリシア文字 ギリシア語
ISO 8859-8 ヘブライ文字 ヘブライ語
ISO 8859-9 (Latin-5) ラテン文字 トルコ語など
ISO 8859-10 (Latin-6) ラテン文字 北欧語など

 このうちISO 8859-1、通称Latin-1が広く使われています。ワークステーションのコンソール画面やxtermなどで8ビットコードを表示させると出てくるのが、このLatin-1です。また、Windowsも「ANSIキャラクタセット」という名前でLatin-1を正式採用しました。それ以外のISO 8859シリーズは、一応国際規格ではありますが、それぞれの言語のコミュニティの外ではあまり目にすることはありません。

 IBMの各コードページやISO 8859のそれぞれは、ISO 646よりもずっと多くの文字を含んでいますので、適用範囲も広く、一つのコード表を複数の国・言語で共通に使うことが可能です。たとえば、Latin-1だけで英語・ドイツ語・フランス語など西欧の主要言語をカバーすることができます。
 しかしまた、ラテン文字のコード表がいくつもあることに気がつくでしょう。これは、アクセント記号付きラテン文字の種類が多すぎて、一つのコード表に入り切れなかった結果です。また、ギリシア文字のようなまったく異なる文字を入れる余地もないので、これまた別のコード表になっています。どうしても混在させたければコード表を切り替えるしかありません。この問題は、8ビットというコード空間が本質的に狭すぎるのが原因であり、複数の国や言語で共通に使えるとはいっても、その範囲は自ずから限られてしまいます。
 とくに8859の場合、当初の目標では、646各国版のようなわずらわしさを避けるために、コード空間を広げた代わりに合成文字を廃止して8ビット固定長にしたのですが、結局は似て非なるコード表がいくつもできてしまい、言語によって切り替えて使わなくてはならないという、646とたいして変わらない状況に陥ってしまいました。

 なお、ISOの8ビットコード(8859に限らず)は、次のような構成になっています。

0x00〜0x1F 制御文字の領域
0x20〜0x7E ASCII図形文字
0x7F 制御文字DEL
0x80〜0x9F 制御文字の領域
0xA0〜0xFF 追加の図形文字

 つまり、右半分にも左半分同様に制御文字の領域があるということです。これについてはISO 2022の解説に譲ります。


[目次へ]

g541119@komaba.ecc.u-tokyo.ac.jp