UTF-8 バリエーションを作ってみました 【変換方式】 よく知られたUTF-8 UCS-4(16進表現) UTF-8(2進表現) 00000000-0000007F 0xxxxxxx 00000080-000007FF 110xxxxx 10xxxxxx 00000800-0000FFFF 1110xxxx 10xxxxxx 10xxxxxx 00010000-001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 00200000-03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 04000000-7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx EBCDICに埋め込むために提案されたUTF-8の変形 UCS-4(16進表現) UTF-8m(2進表現) 00000000-0000007F 0xxxxxxx 00000080-000003FF 110xxxxx 101xxxxx 00000400-00003FFF 1110xxxx 101xxxxx 101xxxxx 00004000-0003FFFF 11110xxx 101xxxxx 101xxxxx 101xxxxx 00040000-003FFFFF 111110xx 101xxxxx 101xxxxx 101xxxxx 101xxxxx 00400000-03FFFFFF 1111110x (101xxxxx) * 5 04000000-3FFFFFFF 11111110 (101xxxxx) * 6 40000000-7FFFFFFF 11111111 (101xxxxx) * 6 C1領域を使わずにできるだけ短く表現するよう工夫したコード UCS-4(16進表現) Offset UTF-8s(2進<16進>) (!) = (10100000<A0>-11011111<DF>) 00000000-0000009F +00000 00000000<00>-10011111<9F> 制御、基本ラテン 000000A0-000002DF +000A0 11100000<E0>-11101000<E8> (!) * 1 ラテン補助など 000002E0-0000FFFF +00000 11101001<E9>-11111000<F8> (!) * 2 BMP 00010000-0010FFFF +10000 11111001<F9>-11111100<FC> (!) * 3 サロゲート相当 00110000-00FFFFFF +00000 11111101<FD> (!) * 4 群00 01000000-7FFFFFFF +00000 11111110<FE>-11111111<FF> (!) * 5 UCS-4全体 unicodeとの相互変換性確保のため0x110000以上をわざと使えないようにしたコード UCS-4(16進表現) Offset UTF-8s'(2進<16進>) (!) = (10100000<A0>-11011111<DF>) 00000000-0000009F +00000 00000000<00>-10011111<9F> 制御、基本ラテン 000000A0-0000039F +000A0 11100000<E0>-11101011<EB> (!) * 1 ラテン、発音記号 000003A0-0000FFFF +00000 11101100<EC>-11111011<FB> (!) * 2 BMP 00010000-0010FFFF +10000 11111100<FC>-11111111<FF> (!) * 3 サロゲート相当 【特徴の比較】 (1)(2)(3)(4)(5)(6)(7)(8)(9) UTF-8 ○ ○ ○ ○ ○ ○ ○ × ○ アラビア文字まで2オクテット以内で表現(7FF) UTF-8m ○ ○ ○ × × × × ○ ○ ギリシア文字まで2オクテット以内で表現(3FF) UTF-8s ○ ○ ○ ○ ○ ○ × ○ × ラテン文字のみ2オクテット以内で表現 (2DF) UTF-8s'○ ○ ○ ○ ○ × × ○ × ラテン文字などを2オクテット以内で表現(39F) (1)文字の先頭の1オクテットを読めば、1文字を構成するオクテット数が判る (2)シーケンスFEFF,FFFE,FFFFが現れない (3)辞書の順序を保存する (4)UCS-2が3オクテット以内で表現できる (5)サロゲート領域に対応する文字が4オクテット以内で表現できる (6)UCS-4が6オクテット以内で表現できる (7)31ビットを超える拡張ができる (8)制御文字(C1)に相当するコードが、図形文字を構成するオクテットに現れない (9)エンコード・デコードが"ビット演算のみ"でできる エンコードアルゴリズムをC言語で説明すると、以下のようになるでしょう テーブルを使うという前提ならば、UTF-8からそんなに効率が落ちるわけではない ことがわかります。 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= /* * UCS-4コードをUTF-8sへ変換するアルゴリズムを説明する例 */ #include <stdio.h> typedef unsigned char OCTET; typedef unsigned long UCS4; typedef struct { OCTET code; UCS4 base; UCS4 offset; size_t length; } XFER_TABLE; /* 変換用配列 */ XFER_TABLE xfer_table[] = { /* code base offset length */ {0x00, 0x00000000, 0x00000000, 0 }, /* 制御文字、基本ラテン */ {0xE0, 0x000000A0, 0x000000A0, 1 }, /* ラテン補助など */ {0xE9, 0x000002E0, 0x00000000, 2 }, /* 群00面00(BMP) */ {0xF9, 0x00010000, 0x00010000, 3 }, /* サロゲート相当 */ {0xFD, 0x00110000, 0x00000000, 4 }, /* 群00 */ {0xFE, 0x01000000, 0x00000000, 5 } /* UCS-4全体 */ }; #define TABLE_LEN (sizeof(xfer_table)/sizeof(XFER_TABLE)) /* * UCS-4コードをUTF-8sへ変換する */ int main(int argc, char *argv[]) { size_t i,k; UCS4 ucs4; OCTET octet[TABLE_LEN+1]; /* 使用法の表示 */ if (argc<2) { fprintf(stderr, "usage: %s UCS4-Code¥n", argv[0]); return(-1); } /* UCS-4コードの取得とUTFパターンの選択 */ sscanf(argv[1], "%li", &ucs4); for (i=0; i<TABLE_LEN-1; i++) { if (xfer_table[i+1].base > ucs4) break; } /* UTFパターンへの変換 */ ucs4 -= xfer_table[i].offset; /* UTF-8(m)ならこの行は不要 */ for (k=xfer_table[i].length; k>0; k--) { octet[k] = (ucs4 & 0x3F) + 0xA0; /* UTF-8(m)ならこの和は"|"でできる */ ucs4 = ucs4 >> 6; } octet[0] = ucs4 + xfer_table[i].code; /* 変換結果の表示 */ printf("%10s => ", argv[1]); for (k=0; k<=xfer_table[i].length; k++) { printf("%02X ", octet[k]); } printf("¥n"); /* 正常終了 */ return 0; }