記録帳

クラウド、データ分析、ウイスキーなど。

UnicodeとUTF-8ってどういう関係があるんだっけ…夏。

最近暑い日が続きますね。皆さんいかがお過ごしでしょうか。
今日は、毎回ググるけど分かった気になって終わってしまう、文字コード関連です。
その中でも、UnicodeUTF-8の関係について記載していこうと思います。

まずは文字コードについて軽く説明をして、そしてUnicodeについてを解説します。
今回は、この本の内容から一部抽出してまとめています。

文字コードとは?

文字集合

文字コードの前に、まずは文字集合です。
文字集合は、文字を重複なく集めた集合のこと。
例えば、以下はひらがなの文字集合です。
これ以外にも、常用漢字文字集合やアルファベットの文字集合など、色々な文字集合があります。

ひらがなの文字集合

文字コード

では、文字コードとは何か。
文字コードは、文字集合の各文字に対するビット組み合わせを一意に定めたものです。
(符号化文字集合とも言います)
例えば、上で示したひらがなの文字集合に対してビット組み合わせを定めた、My文字コードが以下です。

My文字コード

これがPCに実装されていたとしたら、
ビット組み合わせで「000101」「000110」「000111」と入力されたら、「おかき」という文字列が生成されます。

ASCII

その文字コードの中でも、最も基本的なものはASCII(American Standard Code for Information Interchange)です。
ASCIIは7ビットの1バイト文字コードです。つまり、2^7で128個の文字が定められます。
ただ、このすべてに文字が割り当てられているわけではないです。

ASCIIの文字コードは以下です。
英数字の大文字小文字といくつかの記号が割り当てられていますね。

ASCIIの文字コード

https://www.pahoo.org/e-soul/webtech/encode/encode02-01.shtm

このように、ある文字集合があり、それにビット組み合わせを一意に決めたものが文字コードで、色々な種類があります。

UnicodeUTF-8/16/32の関係は?

Unicode

さてここまでで文字コードについてが分かりました。
「じゃあUnicodeってのは文字コードなんだね?!その亜種がUTF-8なのかな?!」
と思うかもしれませんが、落ち着きましょう。
Unicodeは、厳密には文字コード(符号化文字集合)ではありません。
wikipediaには、以下のような記載があります。

Unicodeユニコード)は、符号化文字集合文字符号化方式などを定めた、文字コードの業界規格。文字集合(文字セット)が単一の大規模文字セットであること(「Uni」という名はそれに由来する)などが特徴である。

つまりどういうことだってばよ?と思っていると思います。
私なりの解釈ですが、つまりUnicodeとは、
世界のあらゆる文字を集めた文字集合に対して、それぞれ番号を割り当てた集合
です。ビット組み合わせではなく独自の番号を割り当てているので、文字コードではないのです。

また、Unicodeはめちゃくちゃたくさんの文字を扱っています。先ほどのひらがなであれば2次元の表で表せましたが、Unicodeはなんと4次元で文字と番号を表します。
その4次元とは、群/面/区/点です。4つを指定すると、文字が一意に決まるわけです。
その4つを指定するとき、Unicodeの番号だよということでU+を頭につけて指定します。
例えば、U+306Cは「ぬ」を表します。

UTF-X

Xには8,16,32が入りますが、これは何なのか。
全て、Unicodeで表した番号をビット組み合わせに変換する方式のことを言います。
その変換する方式の違いで、8,16,32が分かれています。

例えば、先ほどの「ぬ」はUnicodeではU+306Cでした。
それが、UTFシリーズでは以下のようなビット組み合わせに変換されます。(16進数で記載)
UTF-8:E3 81 AC(3バイト)
UTF-16:30 6C(2バイト)
UTF-32:00 00 30 6C(4バイト)

さて、それぞれを軽く説明していきます。
先に言っておくと、UTF-32が一番楽に計算できます。次点がUTF-16。一番複雑なのがUTF-8です。(個人の感想)

UTF-32

UTF-32は4バイト固定です。一番容量を食います。
さて、UTF-32は簡単です。Unicodeの番号をそのままビット組み合わせにしたものが、UTF-32です。
Unicodeは群/面/区/点の4次元で文字を指定していると言いました。つまり、4バイトあれば文字を指定できます。
UTF-32は、4バイト確保しているので、そのままビット組み合わせとして指定できるのですね。
「ぬ」の例でも、U+306Cを「00 00 30 6C」と変換していました。そのままですね。

UTF-16

UTF-16は、基本2バイトなんですが一部4バイトになります。
「基本」と書いたのは、Unicodeの中のBMP基本多言語面)に当たるものは2バイトで示せ、それ以外は4バイトになるからです。

はい、BMPの説明をします。
元々Unicodeは、16ビット(2バイト)の組み合わせで生まれました。つまり、2^16通りの文字が表せますね。
ですが、途中で「あかん、これだとたりーん!」となってしまったわけです。
なので、32ビット(4バイト)に拡張しました。
ただ、大体主要な文字は16ビット(2バイト)で表せていたんですね。日本語とか、英数字とか。
そのため、主要なこの16ビット(2バイト)の組み合わせを、BMPと言います。
BMPは2バイトの組み合わせで表現可能なので、群と面が00、00固定となります。

BMP以外の文字の例は、よくこの ほっけ と読む文字が出てきます。
𩸽
これは、Unicodeで言うと「U+00029E3D」になります。群は00ですが、面が02となっています。つまり、BMP外の文字ですね。

さて、UTF-16の説明に戻ります。
このBMPに入っている文字であれば、Unicodeの番号をそのままビット組み合わせに変換できます。
つまり、BMP内であればUTF-16UTF-32も同じ(UTF-32は1,2バイト目が00 00になりますが)です。

では、BMP外の文字を表すとき…その時は、サロゲートペアという仕組みを使います。
この仕組みは、詳しく知りたい方はこの本を買うかググってください。

UTF-8

ラスボスのUTF-8です。
これは、1~4バイトで文字を表します。一番容量がお得な文字コードです。
「ぬ」の例でもありましたが、UTF-8Unicodeの番号と同じようにあらわせません。
そのため、一番複雑です。

UTF-8:E3 81 AC(3バイト)
UTF-16:30 6C(2バイト)
UTF-32:00 00 30 6C(4バイト)

ざっくりいうと、Unicodeの番号をあるルールに則ってUTF-8のバイト列に変換できます。
それが、以下の表です。

UTF-8の変換表

例えば、「ぬ」をUTF-8に変換してみましょう。
Unicodeでは「U+306C」でした。306Cはこの表で言うと3行目に当たりますね。
では次に、306Cは16進数なので、それを2進数に変換すると、こうなります。
0011000001101100
さらにそれを表の右側のバイト列のxに当てはめると、こうなります。
1110xxxx 10xxxxxx 10xxxxxx

11100011 10000001 10101100
さらにさらにこれを16進数したら…「ぬ」のUTF-8でのバイト表現の完成です!
E381AC

ここで確かめてみましたが、合ってそうですね。
【みんなの知識 ちょっと便利帳】URLエンコード/デコードツール = UTF-8

UTF-8変換ツール結果

まとめ

  • ある文字を集めた文字集合に対して、一意のビット組み合わせを割り当てたのが文字コード
  • Unicode文字コードではない。大量の文字に対してそれぞれ番号を割り当てた集合のこと。
  • UTF-8,16,32はそのUnicodeの番号をビット組み合わせに変換する方式。
  • UTF-32は、Unicodeの番号をそのままビット組み合わせにすればOK。
  • UTF-16は、BMPの文字はそのまま2バイトで表せるが、それ以外の文字はサロゲートペアという仕組みで4バイトで表す。
  • UTF-8は、Unicodeの番号をある規則で1~4バイトに変換する。

思ったこと

UTF-8は効率よく文字を表現するためによく使われているのだと思うが、今のメモリが大量に使えるこの時代、全てUTF-32で良いのではないか?と思った。
まぁでも、人間がいちいちUTF-8の計算をするわけでもないし、PCが効率よくさばける方が価値が高いのかな。
とりあえず、UnicodeとUTFシリーズの関係性は理解できた。