Unicode

はじめは16ビット→いろいろあって21ビット

16ビット(2バイト)あれば 216=65536 文字を登録できます。漢字を知っている人ならすぐに足りないと感じますが、最初はこれで全世界の文字を登録できると思っていた様です。

当然不足して、32ビット(4バイト)にする案もあったのですが、いろいろあって結局 21ビット(3バイトより少ない)に落ち着きました。 0~10FFFF です。

16進の1桁は4ビットですから、5桁で20ビット、それに1ビットを足して21ビットです。21ビットで表せる文字数は、221=2097152 ですが、それは 1FFFFF まで使う場合です。実際には 10FFFF までですので 1114112 文字になります。

第0面から第16面までの17面が使えて、1面は16ビットですから、216×17=1114112 です。

Unicodeスカラ値21ビットの使用状況 (1面で 65536 文字)
Unicodeスカラ値の範囲文字説明
0000〜 FFFF第0面基本多言語面(BMP)
10000〜 1FFFF第1面追加多言語面(SMP)
20000〜 2FFFF第2面追加漢字面(SIP)
30000〜 3FFFF第3面第3漢字面(未使用)(TIP)
40000〜 4FFFF第4面未使用・用途未定
50000〜 5FFFF第5面未使用・用途未定
60000〜 6FFFF第6面未使用・用途未定
70000〜 7FFFF第7面未使用・用途未定
80000〜 8FFFF第8面未使用・用途未定
90000〜 9FFFF第9面未使用・用途未定
A0000〜 AFFFF第10面未使用・用途未定
B0000〜 BFFFF第11面未使用・用途未定
C0000〜 CFFFF第12面未使用・用途未定
D0000〜 DFFFF第13面未使用・用途未定
E0000〜 EFFFF第14面追加特殊用途面(SSP)
F0000〜 FFFFF第15面私用面
100000〜10FFFF第16面私用面

Unicodeスカラ値

文字セットは16進数にU+をつけて U+0000~U+10FFFF で表します。これをUnicodeスカラ値といいます。

第0面は16進数で4桁で U+0000~U+FFFF と表します。この16ビット(2バイト)で表現できる部分は65536文字で、ここには基本的な文字を登録してあり、基本多言語面(BMP)と呼ばれます。

BMPの他に16ビット65536文字の面が16あります。0000~FFFF の前に 1,2,3,...D,E,F,10 と 16進数で 1から16 の番号がついていると考えれば理解できると思います。

UTF-16 エンコード

JISで面区点で示された文字を実際に使うときに、ISO-2022-JP,Shift_JIS,EUC-JPなどさまざまなエンコーディングを使用したのと同様に、Unicodeにもたくさんの方式があります。主に使われているのは UTF-8 と UTF-16 の2つです。

UTF-16 具体例

Unicodeスカラ値の第0面(基本多言語面)は、ほとんどそのままUTF-16の文字コード(2バイト=16ビット)になります。

𠀋(じょう)など第0面にない漢字は、サロゲートペアで表します。予約してある2048個のコードを2つ組み合わせて4バイト=32ビットにして表示する仕組みです。

Unicodeスカラ値 と UTF-16
Unicodeスカラ値 文字 UTF-16 説明
U+0041 A 0041 スカラ値がそのまま文字コードになる文字
U+0061 a 0061
U+00E8 è 00E8
U+042F Я 042F
U+2162 2162
U+3042 3042
U+4E9C 4E9C
U+D558 D558
U+2000B 𠀋(じょう) D840 DC0B サロゲートペアを使う文字
U+20BB7 𠮷(よし) D842 DFB7
U+29E3D 𩸽(ほっけ) D867 DE3D

UTF-16 文字の割り当てとサロゲートペアの位置

Unicodeスカラ値の第0面が、ほとんどそのままUTF-16のコードになります。下の表の文字の配置表はそのままUnicodeスカラ値の第0面の配置表でもあります。

上位代用下位代用の部分は文字が直接割り当てられていません。上位代用の2バイトと下位代用の2バイトを組み合わせて第1面から第16面までの文字を表します。これをサロゲートペア(代用対)といいます。

UTF-16はBMPの一部を拡張している。代用対の位置を確認
UTF-16の範囲x000〜x3FFx400〜x7FFx800〜xBFFxC00〜xFFF
0000〜0FFFASCII,ラテン拡張AB,ギリシア,キリル,アラビア,タイ
1000〜1FFFミャンマー,ハングル字母,クメール,モンゴル
2000〜2FFF一般句読点,通貨記号,矢印,数学記号,技術用記号,ラテン拡張C
3000〜3FFFCJKの記号,平仮名,片仮名,CJK統合漢字拡張A
4000〜4FFFCJK統合漢字拡張A, CJK統合漢字
5000〜5FFFCJK統合漢字
6000〜6FFFCJK統合漢字
7000〜7FFFCJK統合漢字
8000〜8FFFCJK統合漢字
9000〜9FFFCJK統合漢字
A000〜AFFFキリル拡張,ラテン拡張D,パスパ,ジャワ,ハングル
B000〜BFFFハングル
C000〜CFFFハングル
D000〜DFFFハングル上位代用下位代用
E000〜EFFF私用領域 (外字領域)
F000〜FFFF私用領域 (外字領域),CJK互換漢字,特殊用途文字

サロゲートペアの上位は U+D800〜U+DBFF, 下位は U+DC00〜U+DFFF で、それぞれ1024字分あります。組み合わせると 1024×1024=1048576文字になります。これで第1面から第16面までの文字 65536×16=1048576文字を表すことができます。

UTF-16 サロゲートペアの計算法

第1面から第16面のユニコードスカラ値を$unicodeとするとサロゲートペアの上位と下位はそれぞれ次のように計算します。

ただし0xは16進数であることを表し、/は切り捨てをする割り算、%は割り算のあまりを求める計算です。

上位 = ($unicode - 0x10000) / 0x400 + 0xD800;
下位 = ($unicode - 0x10000) % 0x400 + 0xDC00;

元に戻すには

$unicode = 0x10000 + (上位 - 0xD800) * 0x400 + (下位 - 0xDC00);

UTF-16 はもともと全部の文字を2バイトで表現できると思っていたときの方式です。Unicodeスカラ値の16進数4桁(2バイト)をそのまま使っていました。

しかし、これでは不足だと分かってから、まだ文字を登録していなかった 0xD800〜0xDFFF の2048文字分の領域に直接文字を割り付けずに、前半の0xD800〜0xDBFFから1文字分、後半0xDC00〜0xDFFFから1文字分のコードを組み合わせて2文字分つまり4バイトで1文字ということにしました。

これにより2048文字分だった範囲を使って 1024×1024=1048576 文字分を生み出したことになります。

UTF-16で表せる文字数の合計を計算する
16ビットで表せる文字数 21665536
サロゲートペアの部分には直接文字を割りつけない1024+1024-2048
サロゲートペアで登録できる文字数1024×10241048576
UTF-16で表せる文字数の合計1112064

UTF-8 エンコード

UTF-8は1~4バイト(初期の定義では6バイトまであった)の可変長コードです。

Unicodeスカラ値とUTF-8
Unicodeスカラ値 文字 UTF-8 説明
U+0041 A 41 1バイト
U+0061 a 61
U+00E8 è C3 A8 2バイト
U+042F Я D0 AF
U+2162 E2 85 A2 3バイト
U+3042 E3 81 82
U+4E9C E4 BA 9C
U+D558 ED 95 98
U+2000B 𠀋(じょう) F0 A0 80 8B 4バイト
U+20BB7 𠮷(よし) F0 A0 AE B7
U+29E3D 𩸽(ほっけ) F0 A9 B8 BD

UTF-8 文字の区切りがわかる仕組み

それぞれの1バイトの値で、それが文字の最初のバイトであるか、2バイト目以降のバイトであるかがわかるようになっています。

コード カテゴリ 備考
00-7x 1バイト文字 US-ASCIIにおなじ
8x,9x,Ax,Bx 多バイト文字の2バイト目以降
Cx,Dx 2バイト文字の開始バイト
Ex 3バイト文字の開始バイト 漢字はおおむねこれで開始
Fx 4バイト以上の文字の開始バイト F0-F7は4バイト、(F8-FBは5バイト、FC-FDは6バイト)

UTF-8 への換算

U+XXXX と表されるUnicodeスカラ値からUTF-8への換算方法です。もちろん逆も可能。

ビットの状態にしてから切り貼りをしています。

Unicodeスカラ値 二進表現 UTF-8 の二進表現
(1) U+ 00 7Fまで 0000 0000 0ppp pppp 0ppp pppp
(2) U+ 07 FFまで 0000 0sss pppp pppp 110s sspp 10pp pppp
(3) U+ FF FFまで ssss ssss pppp pppp 1110 ssss 10ss sspp 10pp pppp
(4) U+ F FF FFまで tttt ssss ssss pppp pppp 1111 00tt 10tt ssss 10ss sspp 10pp pppp
(4') U+ 10 FF FFまで 1 0000 ssss ssss pppp pppp 1111 0100 1000 ssss 10ss sspp 10pp pppp

UTF-8 への換算の具体例

(3)の領域から2つ、(4)から1つ例をあげます。

文字      : 聖
スカラー値: U+8056
          : 8    0    5    6
二進にして: 1000 0000 0101 0110
並べかえて: 1110 1000 1000 0001 1001 0110
16進にして: E    8    8    1    9    6
UTF-8     : E8 81 96
文字      : 愛
スカラー値: U+611B
          : 6    1    1    B
二進にして: 0110 0001 0001 1011
並べかえて: 1110 0110 1000 0100 1001 1011
16進にして: E    6    8    4    9    B
UTF-8     : E6 84 9B
文字      : 𡈽
スカラー値: U+2123D
          : 2    1    2    3    D
二進にして: 0010 0001 0010 0011 1101
並べかえて: 1111 0000 1010 0001 1000 1000 1011 1101
16進にして: F    0    A    1    8    8    B    D
UTF-8     : F0 A1 88 BD

ちなみに、UTF-8に上記の方法で換算するときは、必ずUnicodeスカラ値から換算します。サロケートペアから換算してはいけません。

UTF-8 と UTF-16 の比較

UTF-8 と UTF-16
Unicodeスカラ値 文字 説明 UTF-8 UTF-16
U+0041 A ラテン文字 41 0041
U+0061 a ラテン文字 61 0061
U+00E8 è ラテン文字 C3 A8 00E8
U+042F Я キリル文字(ロシア) D0 AF 042F
U+05D0 א ヘブライ文字 D7 90 05D0
U+0905 デーヴァナーガリ文字 E0 A4 85 0905
U+0E04 タイ文字 E0 B8 84 0E04
U+2162 ローマ数字 E2 85 A2 2162
U+3042 ひらがな E3 81 82 3042
U+4E9C 漢字(あ) E4 BA 9C 4E9C
U+D558 ハングル ED 95 98 D558
U+103A0 𐎠 楔形文字 F0 90 8E A0 D800 DFA0
U+2000B 𠀋 漢字(じょう) F0 A0 80 8B D840 DC0B
U+20BB7 𠮷 漢字(よし) F0 A0 AE B7 D842 DFB7
U+29E3D 𩸽 漢字(ほっけ) F0 A9 B8 BD D867 DE3D