UTF-8 バリエーション


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;
}

トップページ