実はその他にも、文字コードに関してはいろいろ問題があります。たとえば 「日米で円記号とバックスラッシュが違うのはなぜか?」とか、あるいは、ブ ラウザの設定をいろいろいじったりすると現れる「『文字エンコーディン グ』 が変になっているときに表示されるへんなアルファベットの正体 は?」等がありますが、このような問題を解決するには文字コードに関する体 系的な理解が必要となります。ここでは、符号の基礎について学びます。エンジニア志望の人だけでなく、自分でWeb サイトを立ててビジネスを展開し たい人など、広い意味でインターネットでご飯食べたい(仕事をしたい)人に は必須の知識でしょう。自分のサイトでページに文字化けがあったら、お客さ んは逃げていきますよね?
計算機の中において、すべての情報がビット列、すなわち 0/1 の並 び で表現されていることは理解できているとして、それでは、どのよう なビット列を用いて、情報を表現しているのかを考えてみます。
たとえば、学校での成績の記録を考えてみます。仮に合格ないし不合格の
みを表現したいのであれば、1ビットで十分であり、たとえば次のような
対応表が使えます。
合否 | 合格 | 不合格 |
---|---|---|
ビット列 | 1 | 0 |
もちろん、1が不合格・0が合格でもいいわけです(後述)それだけではなく、優・良・可・不可 (A,B,C,D) の記録も残したいとすると、 次のように 2ビットのビット列で表現することになります。
成績 | 優 | 良 | 可 | 不可 |
---|---|---|---|---|
ビット列 | 11 | 10 | 01 | 00 |
このように、何らかの記号ないし記号の列によって情報を表現することを 符号化 と呼び、割り当てられた記号(記号列)を符号 ないしコード (code) と呼びます。
特に、ビット列(2進数)による符号化のことを2進符号化 と言います。 が、現代のコンピュータの文脈では2進符号化 がほとんどなので、わ ざわざ「2進」 をつけて言う場合は少ないです。これらは、要するに、何らかの情報に、なんらかのビット列を割り当てる、と いうことで、そのやり方は本来的には 任意 です。例えば↑の例で言 うと、「優(A判定)」に「00」というビット列を割り当てても、そのシステ ムの利用者全体で了解(統一)されていれば全く問題ない、というわけです。 ただ、みんなでてんでんばらばらな割り当てを行うと、お互いに 意志の疎 通(コミュニケーション) が出来ないので、えいやっ、と決めて、特に 問題が無ければそれにみんなで従う、ということにしているのです。
数値、特に整数の符号化は、基本的には 2進数表現に沿っています。m bit で正 の整数のみを表現する場合には、0 から 2m-1 の範囲の数が表現可 能です。たとえば 4bit であれば、次のように 0 から 15 = 24-1 の数が表現できます。
「表現可能」とは、要するに(合格・不合格のように)情報を区別できる(種 類がある)ので、それぞれのビット列にそれぞれの情報を割り当てる、という ことです。ここで、あらためて2進数について考えてみます。たとえば 4bit (16進数1 桁)であれば、次のように 0 から 15 =24-1 の数(=16通 り)が表現できます(割り当てられています)。
数値 | 0 | 1 | … | 7 | 8 | … | 14 | 15 |
---|---|---|---|---|---|---|---|---|
ビット列 | 0000 | 0001 | … | 0111 | 1000 | … | 1110 | 1111 |
4 ビットの場合だと、ビット列は 16 種類しかない→16通りの区別しか出来な い = 17種類以上の区別は出来ない、ということになります。
現在、多くの計算機では処理の単位(ワード)が32bit 単位で用いられていま して、これは0 から 4294967295 = 232-1 の範囲を表現できます。 加減算などの演算の結果、この範囲を外れてしまうと、当然のことながら正し い結果が表現できずに、別の数値になってしまいます。この表現範囲の限界を 越えることをオーバフロー (overflow) と呼びます。
極端な場合、手の指で数を数えることを考えてください(1進数といえるか も)。この場合、10までしか数えられないですよね?5+6を考えると…指 が足らなくなります。これがオーバフロー なわけです。さて一方、負の整数は、どうように表現すれば良いでしょうか? 日常生活 では「- 1」のように「-(マイナス記号)」を用います。しかし、これでは 「0」「1」以外の記号が必要になり、2進符号化には直接利用できません。 そこで、通常は2の補数 表現と呼ばれる方法を用いて負の整数 を表します。これは、加減算などの演算にあたって、負の数値を正の数値 と同様の方法で扱えるためです。4 ビットの場合で考えなおすと、ビット列は 16 種類しかない→16通りの区別 しか出来ない = 17種類以上の区別は出来ない、ということだったので、0-15 の 16 種類の数値にそれぞれ 0000-1111 のビット列を割り振ったら、16 以上 の数は割り当てられない(言ってみれば、容量が足りなくて器から 溢れ て しまう)→数えられない、ということです。この限界を越えることが すなわちオーバフロー=桁溢れ です。
ちなみに、もし仮に 0000-1111 に 0, 10, 20, ... ,150 を割り振った場合 (事前に決めておけば可能)では、最大で 150 まで数えることは可能です、が、 その場合は 1 とか 2 は表現できない(割り当てられていない=10の倍数しか 数えられない)です。繰返しですが、 4ビットでは16種類しか区別できな い 、ということを再認識してください。
2の補数の作り方ですが、単純にいうと、マイナスの数は、プラスの数の各ビッ トを反転(0なら1、1なら0に)した上で、1を加えます。例えば 4ビット で考えて、「-2」は、「2」が0010 なので、反転させると 1101 で、1 を足した 1110 が2の補数表現となります。
2の補数表現を用いると、 m bit では -2m-1 から
2m-1-1 の範囲の数を表現できます。この場合、正の整数を表す際の
2m-1 から 2m-1 の2進符号を-2m-1 から -1
の表現に用います。たとえば 4bit の場合であれば、次のように -8 =
23 から 7 = 23-1 が表現されます。
数値 | -8 | -7 | … | -1 | 0 | 1 | … | 7 |
---|---|---|---|---|---|---|---|---|
ビット列 | 1000 | 1001 | … | 1111 | 0000 | 0001 | … | 0111 |
この場合、例えば10進数での「5-3」はどう処理されるかということを考 えてみます。「5-3」は「5+(-3)」であり、「5」は 0101、「-3」 は1101 です。よって、この2数を加えると
0101
+1101
------
10010
となり、5ビット目(オーバーフロー)は表現範囲の外なので無視すると
0010 となって、確かに「2」となっています。
いずれにしても、4 ビットの場合だと、ビット列は 16 種類しかない→16通り の区別しか出来ない = 17種類以上の区別は出来ない、ということを再度確認し てください。32bit の場合には、 -2147483648 = -231 から 2147483647 = 231-1 の範囲の数が表現可能です。2の補数表現でオーバ フローが起きると、どうなるでしょうか?この表の場合には、7に1が加わる と -8 に、逆に-8から1が引かれると (+)7 になってしまい ます。つまり、正の数値は負の数値に、負の数値は正の数値に化けてしまいま す。
これも一種のオーバーフローです。絶対値の大きな数値や小数点以下の数値を表現する場合には、 浮動小数点表現(あるいは実数 表現)と呼ばれる符号化を用います。
一般に文字の符号化は、「文字」と「数値」の対として与えられます。ある規 格において、仮名、漢字などのうち、どの文字を対象にするかをまず決めない と符号化する対象がわからないということで、符号化を定めている文字全体の 集合を文字集合(文字セット, character set) と呼び規定します。また、この文字 に対応する数値のことを文字コード (character code) と呼びます。たとえば、 Unicode は、世界の主な文字を文字集合として 16bitの文字コード を定めたもので、現在ではISO 10646 という規格の一部になっています (UCS-2)。またこれを拡張しして4バイトコードにした UCS-4 というのもあり ます。さらに、同じUnicode と同じ文字集合を対象にした 別のコード (符号化) として UTF-8, UTF-16 などがあります。
欧米で用いられるアルファベットは文字の種類が少ないため、少ないビット数で 文字を表現できます。この英数字(アルファベットと数字)の文字コードとしてよ く用いられるのが、ANSIの制定したASCII (American Standard Code for Information Interchange)です。ASCII では 7bit の文字コードを規定しています(後述)。ただし計算機内部では、(主とし てハードウェア的な制約から)通常は、8bit = 1Byte を使って文字を表現しま す。 一方、漢字の表現方法としては、JISコード [ISO-2022-JP] 、 EUCコード [EUC-JP] 、シフトJISコード (SJISコード, Shift_JIS) という異なる3つの方式が広く使われています。これら の方式で、漢字は概ね2Byte で表現されます(後述)。
ちなみにASCII の文字集合は、それぞれの文字の形も簡単です。そのため、 ディスプレイに表示される際やプリンタに印刷される際には、縦横比が 2:1 の、縦に細長い字体が多く用いられます。このような字体の文字を俗 に半角文字 と言います。これに対して、漢字などの文字は文字 の形が複雑なため、一般に縦横比が 1:1 の字体が用いられます。このよ うな字体の文字を俗に全角文字 と言います。これらはあくまで も俗称 である、つまり本来、符号化と文字の大きさに直接 の関係は無い ということを覚えておいてください。
下の表は、ASCII文字コード表(16進数)と呼ばれ るもので、それぞれの文字コード(数値)がどの文字に対応するかを表していま す。左端の数字(0〜7)は、7bitコードの上位の3bitの16進数表現であり、上端 の数字(0〜F)は下位の4bitを表します。つまり、文字コード 28(16)=40(10)は「(」、41(16)= 65(10)は「A」、69(16)=105(10)は「i」 に対応していることがわかります。
下位 4 ビット(16進数表記) | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | ||
上位 3 ビット(16進) | 0 | nul | soh | stx | etx | eot | enq | ack | bel | bs | ht | nl | vt | np | cr | so | si |
1 | dle | dc1 | dc2 | dc3 | dc4 | nak | syn | etb | can | em | sub | esc | fs | gs | rs | us | |
2 | sp | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
3 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? | |
4 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | |
5 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ | |
6 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | |
7 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | del |
図形文字というと●とか▲とかハートマークとか罫線とかを思い浮かべるか もしれませんが、そうではなくて、制御文字に対して、アルファベット・数 字・記号などの目に見える形をもった普通の文字のことです。空白は制御文 字とも図形文字ともみなすことができます。制御コードと「del」(7F(16))は、他の文字とは多少異なります。 たとえば、「bs」(08(16))はバックスペースキー、「esc」 (1B(16))はエスケープキー、「del」(7F(16))はデリー トキーに相当する文字コードです。また「sp」(20(16))は、空白文 字を意味しています。
5c (\) は、本当の ASCII では「\」(バックスラッシュ)の半角なのですが、 JIS を設定するときにここをなぜか \ に入れ替えてしまって、 日本語環境のASCII コード部分が本家 ASCII と互換性が無 く なってしまっています。ちなみに、あとは 7e (~ = tilde) も  ̄(オー バーライン)の半角に入れ替わってますが、こちらは実害は少なそうです(同 じものとみなしても、ほぼ大丈夫)
正確に表示させるためには 1b24 42 24 22 1b 2842 が必要です。 これをASCII で表すと(^[ はエスケープとして) ^[$B$"^[(B となります。 ^[$B はJIS コードの始まり、^[(B は JIS の終り(厳密には ASCII のはじま り)を表す特殊な役割をもった文字列で、 エスケープシーケンス (escape sequence) と呼びます。 なので、本質的には $" の ASCII 2文字 だ、ということです。ここで、全てASCII の範囲内=7bit code で成り立っていることに 注意してください(後述)
JIS: 00100100 00100010 EUC: 10100100 10100010となります。
です。UTF-8, SJIS はさておき、JIS と EUC は比較的簡単に(エスケープシー ケンスの有り無しと、8 ビット目が1か0かを区別することで)コードの変換 ができることに注意してください。
なぜこのように複数のコード系があるか、ですが、歴史的事情としか言いよう がないです…順序としては、まず 7bit-JIS があって、それをベースに MS と NEC が SJIS をつくり、それと平行して DEC などの Unix 陣営が(プログラマ にとって扱いやすい) EUC をあみだした、という感じでしょうか…
但し、最近は MIME の multipart (添付ファイルなどを送るやりかた)で強引 に SJIS や UTF-8 を base64-encoding で送りつける邪悪なメールツー ルもあります (OE 等…)
のちに拡張された JIS X-0213 や、それを包含した ISO-2022-JP-2004 (IANA未 登録) にはローマ数字などは含まれていますが、そもそもメールヘッダでContent-Type: "text/plain; charset=iso-2022-jp"と宣言しておいて(大抵のメールソフトはこう宣言しています。詳細は略しま す)拡張部分を使うというのは明確なルール違反です。とはいえ、自分勝手な 拡張をしているところが(大企業を含めて)多いのも実情です…