エディタを作る 文字コードの歴史
話の脱線ついでに、文字コードの歴史的背景について(私観を交えて)書き留めておく。 プログラミングとは 直接関係ないので興味の無い人は、読み飛ばして欲しい。
1)昔、むかし 漢字なしの時代・・・
コンピュータが発明された英語圏において、画面に文字を表示する際 1文字に当てるデータ量は 7ビット=128種もあれば 十分だった。(アルファベット=26文字、大文字小文字を分けても52文字+α)
日本でコンピュータを使うに当たって、そのコード表の空いている部分にカタカナを割り当てた。 だから、当初のマイコンでは「ひらがな」は表示できす、「カタカナ」で我慢していた事が多い。
このコード体系を ASCII(アスキー、 American Standard Code for Information Interchange)と呼ぶ。 要は、アメリカの文字コード体系である。
アメリカ以外の アルファベット言語圏であれば、かなりの部分が英語と重複しているし 違いのある文字は、空いている場所に十分入る文字数範囲だった訳だ。 その分、国によって、 開発メーカーによって 文字コードの変種が山のように存在した。
例えば、MSXというMicrosoftが主体で開発したパソコンでは、日本語独自の拡張を無理やり?やって なんとか「ひらがな」を表示できるようにしていた。
このような 仮名まで含んだ文字体系を 「ANKコード」と呼ぶ。
(アルファベット、数字(Number)、カナ の合成語)
ところが、漢字を使う文化の国にとっては これでは物足りなくて、やはり漢字が表示出来た方が 便利な訳で、どうにか表示させようと苦心していた。
2)漢字が使える
どこかの学者か役人か?発案者は知らないが、
SO(シフト アウト=0x0E)コードが来たら、ANK→漢字モードに、
SI(シフト イン=0x0F)コードが来たら 漢字→ANKモードに戻す、
というモード切り替えの手法で 漢字を表示させる方法を発案する。
その時に使われていた漢字コードは、主に JISコード。(今はほとんど使われることも無い)
表示モードを切り替えるという 苦肉の策で 数万種類もある漢字が表示できるようにはなったが、扱いに不便な点が多い。
例えば、「文字数を数える」のに単純にバイト数では求められない。 文字列の途中から、文字を切り出す際などは、そこが漢字モードなのか? ANKモードなのか? 文字列の先頭から調べ直さないと判明しない。 これでは不便すぎる。
そこで、Microsoftが知恵を絞って考えたのが 有名な「Shift-JISコード」(シフト ジス コード)
上図の アスキーコード表で、使われていない(黄色の)部分を主に使って 2バイトの組み合わせで 漢字を表現する方法。 これなら「モード切替」という概念を排除できるので、プログラミングでの扱いが かなり楽になる。
例えば、文字列の途中であっても その前後1バイトを見るだけで、漢字(全角)なのか ANK(半角)文字なのかが 判別できる。
また、これまでの JIS漢字コードから(SJISコードに)も、わずかな計算で変換できるよう工夫されている。 良く考えたものだ!
パソコンの世界では、MS-DOSの時代から Windowsの時代に入っても、長らくこの文字コードが標準として使われて来た。 日本では・・・
3)国際化の波
ところが、コンピュータが 世界中で 色々な国で使われるようになると、これでは上手く無いことが分かる。 日本で作られた文章が、他の国では読めず、逆もまたしかりで 「文字化け」して表示される。 インターネットで世界中が結ばれる時代に これでは話にならない。
そこで考え出されたのが UNICODE(ユニコード) UNI=統一、1つの。
世界中の文字を 集約し(一部は切り捨ててでも)、1つの文字コード体系にまとめてしまおうという試み。 1文字2バイトなら65536種類の文字が区別できる訳で、これなら何とか「漢字」も全て入るはず。
必ず1文字が2バイトとシンプルなので、プログラミングする立場からは かなり楽に、便利になる。 現に Windowsの .Net Framework 内部の文字は、UNICODE (UTF-16)を使っていて、それのみに統一されているらしい。
UTF = “Unicode Transformation Format”
コンピュータ発明の当初から、ユニコードが使われていたら、1つの文字コードに統一されていたら、いかに便利で、シンプルにプログラミング出来ていたのだろう?と 思ってしまう。 ただ そんなユニコードにも欠点がある。
4)UTF-16(ユニコード)の欠点
① 問題はこれまで使ってきた Shift-JIS文字との互換性が ほとんど無い点。
ASCII文字を対象にしてきたプログラムがほぼ書きなおし。
そして、もっと大きな問題は 英語圏の人達にとって、
② 普段はアルファベットしか使わないので ユニコードを使うとファイル容量が2倍になる点。
そして、旧文字コードとUNICODEとの互換性の無さに プログラミング作業が複雑になって来る点。(アルファベットも一律2バイトなので処理が異なる)
これら 不便さから、ほとんど使われ無くなってしまっている。 実際・・・
厳密にいうと、まだ いくつか欠点がある。
③ 文字数が足りない
Max65536種類 では、世界中の文字を網羅するには無理がある。 文字数が足りないのだ!
そのため、サロゲート といって、2つの2バイトコードのペア(=4バイト)で 1つの文字を表す、拡張仕様を含めてしまった点。
④ サロゲートペアのため、結局 2バイト固定長では無くなっている。
⑤ エンディアン問題が有る
CPUの種類によって、2バイトの文字コードの 最初に出て来た1バイトを上位とみなすか、下位とみなすかの2種類が存在する。
CPUが ZilogのZ80や Intelのx86 や x64系のCPUなら、リトル エンディアン。 (読み取りづらいが、データ拡張に対して合理的)
最初に出て来た1バイトを下位バイトと見なす。
= UTF-16LE と書く(BOM無し)
68系のMPUのように、(読みやすいけど、こちらの方が小数派かな?)
最初に出て来た1バイトを上位バイトと見なす。
= UTF-16BE と書く(BOM無し)
さらに、これを区別するために 先頭に2バイトの識別コード(BOM)を追加したファイルも存在する。 = UTF-16 と書く(これがBOM付き)
結局 これら3種類のファイルに対応しないといけないのでは、プログラムを書く側からしても大変である。 そして、BOMが無いUTF-16ファイルは 扱わない方が良い。 どちらのエンディアンで格納されているのか不明では、最悪だからだ。
5)UTF-8が主流
その代わりに、現在 デファクト・スタンダードとして使われているのが、UTF-8 という文字コード。 これも 確かにユニコードの一種ではあるが、UTF-16が16ビット=2バイト固定長なのに対し、UTF-8は 1バイト~4バイトの可変長だ。
UNICODEの理想が、全ての文字を固定長にし、プログラミングを楽にする・・・のが、 目的だったはずが、また可変長に戻るのかよ! と突っ込みたくなるが、かなりシンプルな方法で「何バイトのコードなのか?」を計算で求められる。 その点は便利にできている。
そして、これが (この文字コードが使われる) 一番の理由なのだろうが、7Fh以下の ASCIIコードと呼ばれる文字だけを使っている地域の人達にとって、文字処理プログラムをいっさい変更する必要が無い(そのまま使える) そして、当然 ファイル容量も変わらない(00h~7Fhのみ使用の文章なら)
そして、稀に漢字などの多言語を表示する必要が出て来た時は、ちゃんと表示できるわけだ。 (確かに便利かも?)
当然、80h以上の漢字等は、あ UTF-16のユニコードとは、コード値が全く違う。 (これを UNICODEと呼んで良いものか?疑問ではある)
そして、 「エンディアン問題」を無くした。 2バイト以上のコードも 出て来た順番で 文字コードとし、2種類のエンディアンを認めない仕様にしたからだ。
例えば、ひらがなの「あ」の(UTF-8での)文字コードが、
E3h、81h、82h
だったとすると、必ず この順で格納される。 この1種類しか「格納順序」認めないのだ。
ただ、UTF-8にも欠点がある。 それは、ファイルの中身を見ただけでは、このファイルが ASCIIかのか? UTF-8なのか? 判別できない点である。
そこで、UTF-8のファイルにも 先頭にBOMを付ける方式も採用された。 通常、UTF-8とだけ書かれている場合は、ROM付きのファイルである。
UTF-8の場合は、 EFh、BBh、BFhの 3バイトがファイルの先頭にあれば、これが「UTF-8」の文字コードであると分かる。 その時も、”あ” の文字コード並び順は同じだ。
この 先頭のBOMが付いていないファイルを あえて「UTF-8N」(Noneの意味)と呼ぶ。
UTF-8の場合は、この2種類しか存在しないが、BOMが付いていたら、付いていたで、この3バイトが問題を起こす場合もある。
そもそも、エンディアン=バイト・オーダーの区別が無いのに、これを 「BOM」と呼ぶのも おかしな話ではある。
今後、エディタを自分で作る際には、Shift-JISの他に、少なくとも この UTF-8には対応(ファイルの読み書き)できていないと 話にならないだろう。
まっ、でも 現点では、エディタのプログラムの構造を理解しようとする 1つの事例に過ぎないので、ASCII文字だけ(=Shift-JIS)で 動作テストを試しておいて、後でUTF-8に対応する事でも 構わないだろう。
。