Java

          BlogJava 首頁 新隨筆 聯系 聚合 管理
            8 Posts :: 0 Stories :: 1 Comments :: 0 Trackbacks

          字符集簡史

          在所有字符集中,最知名可能 要數被稱為ASCII的7位字符集了。它是美國信息交換標準委員會 (American?Standards?Committee?for?Information?Interchange)的縮寫,?為美國英語通信所設 計。它由128個字符組成,包括大小寫字母、數字0-9、標點符號、非打印字符(換行符、制表符等4個)以及控制字符(退格、響鈴等)組成。

          但 是,由于他是針對英語設計的,當處理帶有音調標號(形如漢語的拼音)的歐洲文字時就會出現問題。因此,創建出了一些包括255個字符的由ASCII擴展的 字符集。其中有一種通常被成為IBM字符集,它把值為128-255之間的字符用于畫圖和畫線,以及一些特殊的歐洲字符。另一種8位字符集是 ISO?8859-1?Latin?1,也簡稱為ISO?Latin-1。它把位于128-255之間的字符用于拉丁字母表中特殊語言字符的編碼,也因此 而得名。

          歐洲語言不是地球上的唯一語言,因此亞洲和非洲語言并不能被8位字符 集所支持。僅漢語(或pictograms)字母表就有80000以上個字符。但是把漢語、日語和越南語的一些相似的字符結合起來,在不同的語言里,使不 同的字符代表不同的字,這樣只用2個字節就可以編碼地球上幾乎所有地區的文字。因此,創建了UNICODE編碼。它通過增加一個高字節對 ISO?Latin-1字符集進行擴展,當這些高字節位為0時,低字節就是ISO?Latin-1字符。UNICODE支持歐洲、非洲、中東、亞洲(包括 統一標準的東亞像形漢字和韓國像形文字)。但是,UNICODE并沒有提供對諸如Braille,?Cherokee,?Ethiopic, ?Khmer,?Mongolian,?Hmong,?Tai?Lu,?Tai?Mau文字的支持。同時它也不支持如Ahom,?Akkadian, ?Aramaic,?Babylonian?Cuneiform,?Balti,?Brahmi,?Etruscan,?Hittite,?Javanese, ?Numidian,?Old?Persian?Cuneiform,?Syrian之類的古老的文字。

          事 實證明,對可以用ASCII表示的字符使用UNICODE并不高效,因為UNICODE比ASCII占用大一倍的空間,而對ASCII來說高字節的0對他 毫無用處。為了解決這個問題,就出現了一些中間格式的字符集,他們被稱為通用轉換格式,既UTF (Universal?Transformation?Format)。目前存在的UTF格式有:UTF-7,?UTF-7.5,?UTF-8,?UTF -16,?以及?UTF-32。本文討論UTF-8字符集的基礎。

          UTF_8字符集

          UTF -8是UNICODE的一種變長字符編碼,由Ken?Thompson于1992年創建。現在已經標準化為RFC?3629。UTF-8用1到6個字節編 碼UNICODE字符。如果UNICODE字符由2個字節表示,則編碼成UTF-8很可能需要3個字節,而如果UNICODE字符由4個字節表示,則編碼 成UTF-8可能需要6個字節。用4個或6個字節去編碼一個UNICODE字符可能太多了,但很少會遇到那樣的UNICODE字符。

          UFT-8轉換表表示如下:

          UNICODE?UTF-8?
          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?

          實 際表示ASCII字符的UNICODE字符,將會編碼成1個字節,并且UTF-8表示與ASCII字符表示是一樣的。所有其他的UNCODE字符轉化成 UTF-8將需要至少2個字節。每個字節由一個換碼序列開始。第一個字節由唯一的換碼序列,由n位1加一位0組成。n位1表示字符編碼所需的字節數。

          示例

          UNICODE?uCA(11001010)?編碼成UTF-8將需要2個字節:

          uCA?->?C3?8A

          1100?1010
          110xxxxx?10xxxxxx

          1100?1010?->?110xxxxx?10xxxxxx
          ->?110xxxxx?10xxxxx0
          ->?110xxxxx?10xxxx10
          ->?110xxxxx?10xxx010
          ->?110xxxxx?10xx1010
          ->?110xxxxx?10x01010
          ->?110xxxxx?10001010
          ->?110xxxx1?10001010
          ->?110xxx11?10001010
          ->?11000011?10001010
          ->?C3?8A

          UNICODE?uF03F?(11110000?00111111)?編碼成UTF-8將需要3個字節:

          u?F03F?->?EF?80?BF

          1111?0000?0011?1111?->?1110xxxx?10xxxxxx?10xxxxxx
          ->?11101111?10000000?10111111
          ->?EF?80?BF

          譯者注:由上分析可以看到,UNCODE到UTF-8的轉換就是先確定編碼所需要的字節數,然后用UNICODE編碼位從低位到高位依次填入上面表示為x的位上,不足的高位以0補充。以上是個人經驗,如有錯誤,請不惜指教,謝過先:)

          UTF-8編碼的優點:

          UTF-8編碼可以通過屏蔽位和移位操作快速讀寫。
          字符串比較時strcmp()和wcscmp()的返回結果相同,因此使排序變得更加容易。
          字節FF和FE在UTF-8編碼中永遠不會出現,因此他們可以用來表明UTF-16或UTF-32文本(見BOM)
          UTF-8?是字節順序無關的。它的字節順序在所有系統中都是一樣的,因此它實際上并不需要BOM。

          UTF-8編碼的缺點:

          你無法從UNICODE字符數判斷出UTF-8文本的字節數,因為UTF-8是一種變長編碼
          它需要用2個字節編碼那些用擴展ASCII字符集只需1個字節的字符
          ISO?Latin-1?是UNICODE的子集,但不是UTF-8的子集
          8位字符的UTF-8編碼會被email網關過濾,因為internet信息最初設計為7為ASCII碼。因此產生了UTF-7編碼。
          UTF-8?在它的表示中使用值100xxxxx的幾率超過50%,?而現存的實現如ISO?2022,?4873,?6429,?和8859系統,會把它錯認為是C1?控制碼。因此產生了UTF-7.5編碼。

          修正的UTF-8:


          java使用UTF-16表示內部文本,并支持用于字符串串行化的非標準的修正UTF-8編碼。標準UTF-8和修正的UTF-8有兩點不同:
          修 正的UTF-8中,null字符編碼成2個字節(11000000?00000000)?而不是標準的1個字節(00000000),這樣作可以保證編碼 后的字符串中不會嵌入null字符。因此如果在類C語言中處理字符串,文本不會在第一個null字符時截斷(C字符串以null結尾)。
          在標準 UTF-8編碼中,超出基本多語言范圍(BMP?-?Basic?Multilingual?Plain)的字符被編碼為4字節格式,但是在修正的UTF -8編碼中,他們由代理編碼對(surrogate?pairs)表示,然后這些代理編碼對在序列中分別重新編碼。結果標準UTF-8編碼中需要4個字節 的字符,在修正后的UTF-8編碼中將需要6個字節。

          位序標志BOM


          BOM(Byte?Order?Mark)是一個字符,它表明UNICODE文本的UTF-16,UTF-32的編碼字節順序(高字節低字節順序)和編碼方式(UTF-8,UTF-16,UTF-32,?其中UTF-8編碼是字節順序無關的)。

          如下所示:

          Encoding?Representation?
          UTF-8?EF?BB?BF?
          UTF-16?Big?Endian?FE?FF?
          UTF-16?Little?Endian?FF?FE?
          UTF-32?Big?Endian?00?00?FE?FF
          UTF-32?Little?Endian?FF?FE?00?00

          UTF-8?C++?程序編碼示例:

          下面是四個C++函數,他們分別實現2字節和4字節UNICODE和UTF-8之間的轉換。

          #define?MASKBITS?0x3F
          #define?MASKBYTE?0x80
          #define?MASK2BYTES?0xC0
          #define?MASK3BYTES?0xE0
          #define?MASK4BYTES?0xF0
          #define?MASK5BYTES?0xF8
          #define?MASK6BYTES?0xFC

          typedef?unsigned?short?Unicode2Bytes;
          typedef?unsigned?int?Unicode4Bytes;

          void?UTF8Encode2BytesUnicode(std::vector<?Unicode2Bytes?>?input,
          std::vector<?byte?>&?output)
          {
          for(int?i=0;?i?<?input.size();?i++)
          {
          //?0xxxxxxx
          if(input?<?0x80)
          {
          output.push_back((byte)input);
          }
          //?110xxxxx?10xxxxxx
          else?if(input?<?0x800)
          {
          output.push_back((byte)(MASK2BYTES?|?input?>>?6));
          output.push_back((byte)(MASKBYTE?|?input?&?MASKBITS));
          }
          //?1110xxxx?10xxxxxx?10xxxxxx
          else?if(input?<?0x10000)
          {
          output.push_back((byte)(MASK3BYTES?|?input?>>?12));
          output.push_back((byte)(MASKBYTE?|?input?>>?6?&?MASKBITS));
          output.push_back((byte)(MASKBYTE?|?input?&?MASKBITS));
          }
          }
          }

          void?UTF8Decode2BytesUnicode(std::vector<?byte?>?input,
          std::vector<?Unicode2Bytes?>&?output)
          {
          for(int?i=0;?i?<?input.size();)
          {
          Unicode2Bytes?ch;

          //?1110xxxx?10xxxxxx?10xxxxxx
          if((input?&?MASK3BYTES)?==?MASK3BYTES)
          {
          ch?=?((input?&?0x0F)?<<?12)?|?(
          (input[i+1]?&?MASKBITS)?<<?6)
          |?(input[i+2]?&?MASKBITS);
          i?+=?3;
          }
          //?110xxxxx?10xxxxxx
          else?if((input?&?MASK2BYTES)?==?MASK2BYTES)
          {
          ch?=?((input?&?0x1F)?<<?6)?|?(input[i+1]?&?MASKBITS);
          i?+=?2;
          }
          //?0xxxxxxx
          else?if(input?<?MASKBYTE)
          {
          ch?=?input;
          i?+=?1;
          }

          output.push_back(ch);
          }
          }

          void?UTF8Encode4BytesUnicode(std::vector<?Unicode4Bytes?>?input,
          std::vector<?byte?>&?output)
          {
          for(int?i=0;?i?<?input.size();?i++)
          {
          //?0xxxxxxx
          if(input?<?0x80)
          {
          output.push_back((byte)input);
          }
          //?110xxxxx?10xxxxxx
          else?if(input?<?0x800)
          {
          output.push_back((byte)(MASK2BYTES?|?input?>?6));
          output.push_back((byte)(MASKBYTE?|?input?&?MASKBITS));
          }
          //?1110xxxx?10xxxxxx?10xxxxxx
          else?if(input?<?0x10000)
          {
          output.push_back((byte)(MASK3BYTES?|?input?>>?12));
          output.push_back((byte)(MASKBYTE?|?input?>>?6?&?MASKBITS));
          output.push_back((byte)(MASKBYTE?|?input?&?MASKBITS));
          }
          //?11110xxx?10xxxxxx?10xxxxxx?10xxxxxx
          else?if(input?<?0x200000)
          {
          output.push_back((byte)(MASK4BYTES?|?input?>>?18));
          output.push_back((byte)(MASKBYTE?|?input?>>?12?&?MASKBITS));
          output.push_back((byte)(MASKBYTE?|?input?>>?6?&?MASKBITS));
          output.push_back((byte)(MASKBYTE?|?input?&?MASKBITS));
          }
          //?111110xx?10xxxxxx?10xxxxxx?10xxxxxx?10xxxxxx
          else?if(input?<?0x4000000)
          {
          output.push_back((byte)(MASK5BYTES?|?input?>>?24));
          output.push_back((byte)(MASKBYTE?|?input?>>?18?&?MASKBITS));
          output.push_back((byte)(MASKBYTE?|?input?>>?12?&?MASKBITS));
          output.push_back((byte)(MASKBYTE?|?input?>>?6?&?MASKBITS));
          output.push_back((byte)(MASKBYTE?|?input?&?MASKBITS));
          }
          //?1111110x?10xxxxxx?10xxxxxx?10xxxxxx?10xxxxxx?10xxxxxx
          else?if(input?<?0x8000000)
          {
          output.push_back((byte)(MASK6BYTES?|?input?>>?30));
          output.push_back((byte)(MASKBYTE?|?input?>>?18?&?MASKBITS));
          output.push_back((byte)(MASKBYTE?|?input?>>?12?&?MASKBITS));
          output.push_back((byte)(MASKBYTE?|?input?>>?6?&?MASKBITS));
          output.push_back((byte)(MASKBYTE?|?input?&?MASKBITS));
          }
          }
          }

          void?UTF8Decode4BytesUnicode(std::vector<?byte?>?input,
          std::vector<?Unicode4Bytes?>&?output)
          {
          for(int?i=0;?i?<?input.size();)
          {
          Unicode4Bytes?ch;

          //?1111110x?10xxxxxx?10xxxxxx?10xxxxxx?10xxxxxx?10xxxxxx
          if((input?&?MASK6BYTES)?==?MASK6BYTES)
          {
          ch?=?((input?&?0x01)?<<?30)?|?((input[i+1]?&?MASKBITS)?<<?24)
          |?((input[i+2]?&?MASKBITS)?<<?18)?|?((input[i+3]
          &?MASKBITS)?<<?12)
          |?((input[i+4]?&?MASKBITS)?<<?6)?|?(input[i+5]?&?MASKBITS);
          i?+=?6;
          }
          //?111110xx?10xxxxxx?10xxxxxx?10xxxxxx?10xxxxxx
          else?if((input?&?MASK5BYTES)?==?MASK5BYTES)
          {
          ch?=?((input?&?0x03)?<<?24)?|?((input[i+1]
          &?MASKBITS)?<<?18)
          |?((input[i+2]?&?MASKBITS)?<<?12)?|?((input[i+3]
          &?MASKBITS)?<<?6)
          |?(input[i+4]?&?MASKBITS);
          i?+=?5;
          }
          //?11110xxx?10xxxxxx?10xxxxxx?10xxxxxx
          else?if((input?&?MASK4BYTES)?==?MASK4BYTES)
          {
          ch?=?((input?&?0x07)?<<?18)?|?((input[i+1]
          &?MASKBITS)?<<?12)
          |?((input[i+2]?&?MASKBITS)?<<?6)?|?(input[i+3]?&?MASKBITS);
          i?+=?4;
          }
          //?1110xxxx?10xxxxxx?10xxxxxx
          else?if((input?&?MASK3BYTES)?==?MASK3BYTES)
          {
          ch?=?((input?&?0x0F)?<<?12)?|?((input[i+1]?&?MASKBITS)?<<?6)
          |?(input[i+2]?&?MASKBITS);
          i?+=?3;
          }
          //?110xxxxx?10xxxxxx
          else?if((input?&?MASK2BYTES)?==?MASK2BYTES)
          {
          ch?=?((input?&?0x1F)?<<?6)?|?(input[i+1]?&?MASKBITS);
          i?+=?2;
          }
          //?0xxxxxxx
          else?if(input?<?MASKBYTE)
          {
          ch?=?input;
          i?+=?1;
          }
          output.push_back(ch);
          }
          }


          限譯者水平有限,有不解之處請參考原文。版權屬原文作者所有,轉載請注明出處及作者。

          原文參見:http://www.codeguru.com/Cpp/misc ... article.php/c10451/

          posted on 2006-06-29 16:00 java執著者 閱讀(2240) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 青铜峡市| 原阳县| 七台河市| 鹤峰县| 余江县| 鸡泽县| 望都县| 小金县| 河东区| 遂川县| 汤阴县| 富民县| 威远县| 龙门县| 博白县| 新乡市| 平塘县| 高青县| 福建省| 额济纳旗| 吐鲁番市| 尼木县| 宝山区| 锡林浩特市| 杭州市| 台东市| 叙永县| 崇仁县| 紫阳县| 内黄县| 绿春县| 社会| 会昌县| 浦县| 富川| 进贤县| 鄄城县| 青川县| 武宣县| 海南省| 青神县|