UTF-8編碼法


作者:Владимир Лесной

Lastest update : 2014/11/12


本篇說明中文語言方程當中,CLF數學碼與UTF-8編碼的混和使用狀況。

CLF數學碼是個32位元的文字數據,在C語言當中,實際可以精確表達的是「uint32_t」, 有些平台使用的「wchar_t」實際上是16位元, 有些平台則實際上是「int32_t」。由於中文語言 方程使用C++,因此,一般而言,preprocessor會想辦法將這個問題自動消除掉。用戶不應該自行另外定義一個其他的處理型態,而應該使 用LfChar的類別。

UTF-8的定義區域如下:

LFE碼開始位置
LFE碼結尾位置
UTF-8
註釋
LF+00000000
LF+0000007F 00000000 00000000 00000000 0zzzzzzz
0zzzzzzz(00-7F)
一個位元組。
LF+00000080
LF+000007FF 00000000 00000000 00000yyy yyzzzzzz
110yyyyy(C0-DF)
10zzzzzz(80-BF)
兩個位元組。
LF+00000800
LF+0000D7FF 00000000 00000000 xxxxyyyy yyzzzzzz
1110xxxx(E0-EF)
10yyyyyy
10zzzzzz
三個位元組。
LF+0000D800
LF+0000DFFF

UTF-16擴展標識輔助平面。
LF+0000E000
LF+0000FFFF 00000000 00000000 xxxxyyyy yyzzzzzz
1110xxxx(E0-EF)
10yyyyyy
10zzzzzz
三個位元組。
LF+00010000
LF+0010FFFF 00000000 000wwwxx xxxxyyyy yyzzzzzz
11110www(F0-F7)
10xxxxxx
10yyyyyy
10zzzzzz
四個位元組。
LF+00110000
LF+001FFFFF

LFE碼當中預留區。
LF+80000000
LF+8FFFFFFF


CLF數學碼當中,單部件(1,2,4,10,18,20)編碼區。
LF+90000000
LF+9FFFFFFF


CLF數學碼當中,雙部件直排編碼區。
LF+A0000000
LF+AFFFFFFF

CLF數學碼當中,雙部件橫排編碼區。
LF+B0000000 LF+BFFFFFFF

CLF數學碼當中,雙部件除去直排及橫排的編碼區。
LF+C0000000 LF+CFFFFFFF

CLF數學碼當中,多於兩個部件(7,13,14,17,19,21,31,33...)的編碼 區。
LF+D8000000
LF+DFFFFFFF


LFE碼當中為UTF-16預留的處理區域。
LF+EFBBBF00 LF+EFBBBFFF


UTF-8 Marking(EF,BB,BF)
LF+FC000000
LF+FCFFFFFF


賦意域標記碼。
LF+FEFF0000
LF+FEFFFFFF


UTF-16BE BOM
UTF-8 Marking(EF,BB,BF)
LF+FFFE0000
LF+FFFEFFFF


UTF-16LE BOM
LF+FFFFFE00
LF+FFFFFEFF

LFE碼當中的數值區。

明確的說,UTF-8針對U+00010000-U+0010FFFF區域的編碼,轉換到32位元時,與LF數學碼衝突,因此,CLF系統最後是 採用UTF-16來處理實際的編碼。

LFE碼與UTF-8之間的轉換


CLF數學碼是LFE碼(Language Formula Encoding,語言方程碼)的一個子集合,LFE碼當中,很多是無法轉換到現有的國際標準編碼,這包含了Unicode。語言方程碼並不被建議作為交 換標準,在CIOS的語言學次系統當中,LFE碼是作為計算語言學上的運算碼。

只有一部分的LFE碼可以被轉換到UTF-8。

UTF-8轉換到CLF語言方程碼Unicode區域的 演算法
int Utf8ToLFE(unsigned char * utf8,uint32_t * LFE,int maxlen)
{
  if ( NULL == LFE  ) return 0 ;
 
if ( NULL == utf8 ) return 0 ;
  unsigned char   c            ;
  unsigned char * p   = utf8   ;
  int             len = 0      ;
  while ( 0 != (*p) )          {
    if ( 0x80 > (*p) )         {
      *LFE = (uint32_t)(*p)    ;
      LFE++                    ;
      len++                    ;
    } else
    if ( 0xE0 > (*p) )         {
      *LFE  = (uint32_t)(*p)   ;
      *LFE &= 0x1F             ;
      p++                      ;
      c     = (*p)             ;
      if ( 0x80 > c )          {
        *LFE = 0               ;
        return len             ;
      }                        ;
      c     &= 0x3F            ;
      *LFE <<= 6               ;
      *LFE  |= (uint32_t)c     ;
      LFE++                    ;
      len++                    ;
   
} else                     {
    if ( 0xF0 > (*p) )         {
      *LFE  = (uint32_t)(*p)   ;
      *LFE &= 0x0F             ;
      p++                      ;
      c     = (*p)             ;
      if ( 0x80 > c )          {
        *LFE = 0               ;
        return len             ;
      }                        ;
      c     &= 0x3F            ;
      *LFE <<= 6               ;
      *LFE  |= (uint32_t)c     ;
      p++                      ;
      c     = (*p)             ;
      if ( 0x80 > c )          {
        *LFE = 0               ;
        return len             ;
      }                        ;
      c     &= 0x3F            ;
      *LFE <<= 6               ;
      *LFE  |= (uint32_t)c     ;
      LFE++                    ;
      len++                    ;
   
} else
    if (
0xF8 > (*p) )         {
      *LFE  = (uint32_t)(*p)   ;
      *LFE &= 0x07             ;
      p++                      ;
      c     = (*p)             ;
      if ( 0x80 > c )          {
        *LFE = 0               ;
        return len             ;
      }                        ;
      c     &= 0x3F            ;
      *LFE <<= 6               ;
      *LFE  |= (uint32_t)c     ;
      p++                      ;
      c     = (*p)             ;
      if ( 0x80 > c )          {
        *LFE = 0               ;
        return len             ;
      }                        ;
      c     &= 0x3F            ;
      *LFE <<= 6               ;
      *LFE  |= (uint32_t)c     ;
      p++                      ;
      c     = (*p)             ;
      if ( 0x80 > c )          {
        *LFE = 0               ;
        return len             ;
      }                        ;
      c     &= 0x3F            ;
      *LFE <<= 6               ;
      *LFE  |= (uint32_t)c     ;
      LFE++                    ;
      len++                    ;
   
} else                     {
      /* 0xF8 - 0xFF          */
      /* UTF-8 does not contains this region */
      *LFE = 0                 ;
      return len               ;
    }                          ;

    p++                        ;
  }                            ;
  *LFE = 0                     ;
  return len                   ;
}


UTF-8轉換到LFE碼以後,所佔區域即為LFE碼當中為辨識Unicode所保留的區域(0x00000000-0x001FFFFF)。

這個演算法並未實際考慮到U+0000D800 - U+0000DFFF區 域的辨識,故僅為示範作用的轉換演算法。