Inside PRESSBLOG

PRESSBLOG / Instagram / SNS マーケティングとか

絵文字の処理にハマった時に、文字コードとエンコードについて勉強した

こんにちは、PRESSのエンジニアをしているさいぬです。

絵文字を含む文字列の文字数をカウントする時、絵文字の処理にハマり、絵文字もとい文字コードについてちゃんと知らないなぁということで色々勉強したことをまとめます。

はじめに

絵文字について理解するにあたり、主に以下のことについて学びました。

  1. 文字コード
  2. Unicode
  3. UTF-8, UTF-16
  4. サロゲートペア
  5. 絵文字の仕組み
  6. 合字とZero Width Joiner

今回は、文字コード・Unicode・UTF-8, UTF-16・サロゲートペアについて書きます。

文字コード

コンピュータ上で扱う対象となる文字を列挙して集めたものを文字集合という。

アルファベットの大文字小文字、数字、カンマやピリオド、ひらがな、カタカナ、漢字、句読点、括弧などの記号など。

A B C D ...
1 2 3 4 ...
あ い う え ...
山 川「 」 。 、 ...

これらの文字を特定するために一意な番号で表した文字集合を符号化文字集合という。例えば、Aは33、Bは34のように。(番号は適当)

このA⇔33のような対応を文字コードといい、一意な番号のことをコードポイントという。

Unicode

Unicodeは今世界中で使われている13万を超える様々な文字を集約した符号化文字集合をもつ規格。

Unicodeの特徴は、

  • 13万を超える豊富な符号化文字集合
  • テキストに左からの横書きと右からの横書きを混在させる双方向アルゴリズムや文字列同士を比較するアルゴリズム

などをもつ非常に大きな規格になっている。

13万の文字集合には、一つ一つにUnicodeスカラ値(コードポイント)と呼ばれる番号が振られている。

Unicodeスカラ値

U+を付けた4ケタから6ケタの16進数で、U+3042のように表される。

エンコーディング

Unicodeスカラ値など符号化文字集合に使われている文字を一意に特定するためのものをコードポイントと言った。

このコードポイントを様々なバイト形式で符号化することを、文字符号化方式またはエンコーディングという。(UTF-8やShift_JIS、EUC-JPなど)

バイト

ここで一旦バイトやビット組み合わせについて軽く解説を挟む。知っている人は飛ばしてください。

コンピューターで扱われるデータは、ビット(binary digit; bit)とバイト(byte)という単位で扱われる。

ビットは、コンピュータ内部における情報表現の最小単位である。1ビットでは0または1が格納され、表現数は2である。4ビットの表現数は、24=16だ。

1バイトは、8ビットの集合体のこと。表現数は、28=256。

16進数は、1ケタを0~9, A~Fの16文字で表現する文字。(10進数は1ケタを0~9の10文字で表現する私たちがいつも使っている表現方法)

1バイトは、以下のような2ケタの16進数(256通り)で表されることが多い。

0x00, 0x01, ・・・0x09, 0x0A, ・・・0x0F(10進数だと0~16)
0x10, 0x11, ・・・0x19, 0x1A, ・・・0x1F(10進数だと17~32)
・・・
0xF0, 0xF1, ・・・0xF9, 0xFA, ・・・0xFF(10進数だと240~256)

0xは16進数で表す時に先頭につける文字

「0x83 0xE3」のようなバイト列で表現したものをバイト形式という。

UTF-8, UTF-16

Unicodeをファイルやメモリ上で表現するためのエンコーディング。

UTF-8

Unicodeの1文字を1~4バイトの可変長で表現する方法。

Unicodeスカラ値 1バイト目 2バイト目 3バイト目 4バイト目
U+0000~U+007F 0x00~0x7F
U+0080~U+07FF 0xC2~0xDF 0x80~0xBF
U+0800~U+FFFF 0xE0~0xEF 0x80~0xBF 0x80~0xBF
U+10000~U+1FFFFF 0xF0~0xF7 0x80~0xBF 0x80~0xBF 0x80~0xBF

U+0000~U+007Fが0x00~0x7FになっているのはASCII*1と互換性を持たせるため。

UTF-16

Unicodeのエンコーディングの1つで、1文字を16ビット(2バイト)または32ビット(4バイト)で表す。

Unicodeスカラ値をそのまま16bit表現に利用できる範囲

Unicodeスカラ値 UTF-16
U+0000~U+D7FF 0x0000~0xD7FF
U+E000~U+FFFF 0xE000~0xFFFF

2つの16bitで表現する範囲

Unicodeスカラ値 UTF-16
U+10000~U+10FFFF 0xD800~0xDBFFと0xDC00~0xDFFF

試しにエンコード / デコードサイトで文字列をUTF-8とUTF-16に変換してみる。

文字 UTF-8 UTF-16
P U+50 U+0050
R U+52 U+0052
E U+45 U+0045
S U+53 U+0053
U+E381AE U+306E
U+E38195 U+3055
U+E38184 U+3044
U+E381AC U+306C
😎 U+F09F988E U+D83DU+DE0E

PRESSはASCIIなので、コードポイントが同じ
😎はUTF-16では2つの16bitで表されている

この2つの16bitで1つの文字を表現する方法をサロゲートペアという。

サロゲートペア

Unicodeのコードポイント(Unicodeスカラ値)は16bitで、16進数で書くと4ケタになることはすでに話した通り。(U+0000)

16bitでは表現数は、216=65536。つまり、6万5536文字しか表現することができない。 一方、漢字は8万字程度をUnicodeの符号化文字集合に収録したいので、16進数4ケタ(16bit)では表現しきれなくなった。

しかし、Unicodeでは16進数5ケタの20bitをそのまま扱えないらしいので、16bitを2つ組み合わせることによって表現することになった。

例えば、0x2000B0xD840 0xDC0Bという組み合わせに処理される。

このように、16進数4ケタに収まり切らなかったコードポイントを2つの16進数4ケタの組み合わせをサロゲートペアという。

まとめ

絵文字の仕組みについては次の記事に書きます。

参考

*1:英数字、制御コードやいくつかの記号に対し、7ビットで0x00~0x7Fまでのビット組み合わせを与えた規格。