Unicode 的編碼和實現

來源:互聯網
上載者:User

大概來說,Unicode 編碼系統可分為編碼方式和實現方式兩個層次。
 

 

  1.編碼方式
 

 

  Unicode是國際組織制定的可以容納世界上所有文字和符號的字元編碼方案。Unicode用數字0-0x10FFFF來映射這些字元,最多可以容納1114112個字元,或者說有1114112個碼位。碼位就是可以分配給字元的數字。UTF-8、UTF-16、UTF-32都是將數字轉換到程式資料的編碼方案。
 

 

  Unicode字元集可以簡寫為UCS(Unicode Character Set)。早期的Unicode標準有UCS-2、UCS-4的說法。UCS-2用兩個位元組編碼,UCS-4用4個位元組編碼。UCS-4根據最高位為0的最高位元組分成2^7=128個group。每個group再根據次高位元組分為256個平面(plane)。每個平面根據第3個位元組分為256行 (row),每行有256個碼位(cell)。group 0的平面0被稱作BMP(Basic Multilingual Plane)。將UCS-4的BMP去掉前面的兩個零位元組就得到了UCS-2。
 

 

  每個平面有2^16=65536個碼位。Unicode計劃使用了17個平面,一共有17*65536=1114112個碼位。在Unicode 5.0.0版本中,已定義的碼位只有238605個,分布在平面0、平面1、平面2、平面14、平面15、平面16。其中平面15和平面16上只是定義了兩個各佔65534個碼位的專用區(Private Use Area),分別是0xF0000-0xFFFFD和0x100000-0x10FFFD。所謂專用區,就是保留給大家放自訂字元的地區,可以簡寫為PUA。
 

 

  平面0也有一個專用區:0xE000-0xF8FF,有6400個碼位。平面0的0xD800-0xDFFF,共2048個碼位,是一個被稱作代理區(Surrogate)的特殊地區。代理區的目的用兩個UTF-16字元表示BMP以外的字元。在介紹UTF-16編碼時會介紹。
 

 

  如前所述在Unicode 5.0.0版本中,238605-65534*2-6400-2408=99089。餘下的99089個已定義碼位分布在平面0、平面1、平面2和平面14上,它們對應著Unicode目前定義的99089個字元,其中包括71226個漢字。平面0、平面1、平面2和平面14上分別定義了52080、3419、43253和337個字元。平面2的43253個字元都是漢字。平面0上定義了27973個漢字。
 

 

  2.實現方式
 

 

  在Unicode中:漢字“字”對應的數字是23383。在Unicode中,我們有很多方式將數字23383表示成程式中的資料,包括:UTF-8、UTF-16、UTF-32。UTF是“UCS Transformation Format”的縮寫,可以翻譯成Unicode字元集轉換格式,即怎樣將Unicode定義的數字轉換成程式資料。例如,“漢字”對應的數字是0x6c49和0x5b57,而編碼的程式資料是:
 

 

  BYTE data_utf8[] = {0xE6, 0xB1, 0x89, 0xE5, 0xAD, 0x97}; // UTF-8編碼
 

 

  WORD data_utf16[] = {0x6c49, 0x5b57}; // UTF-16編碼
 

 

  DWORD data_utf32[] = {0x6c49, 0x5b57}; // UTF-32編碼
 

 

  這裡用BYTE、WORD、DWORD分別表示無符號8位整數,無符號16位整數和無符號32位整數。UTF-8、UTF-16、UTF-32分別以BYTE、WORD、DWORD作為編碼單位。“漢字”的UTF-8編碼需要6個位元組。“漢字”的UTF-16編碼需要兩個WORD,大小是4個位元組。“漢字”的UTF-32編碼需要兩個DWORD,大小是8個位元組。根據位元組序的不同,UTF-16可以被實現為UTF-16LE或UTF-16BE,UTF-32可以被實現為UTF-32LE或UTF-32BE。下面介紹UTF-8、UTF-16、UTF-32、位元組序和BOM。
 

 

  UTF-8
 

 

  UTF-8以位元組為單位對Unicode進行編碼。從Unicode到UTF-8的編碼方式如下:
 

 

  Unicode編碼(16進位) ║ UTF-8 位元組流(二進位)
 

 

  000000 - 00007F ║ 0xxxxxxx
 

 

  000080 - 0007FF ║ 110xxxxx 10xxxxxx
 

 

  000800 - 00FFFF ║ 1110xxxx 10xxxxxx 10xxxxxx
 

 

  010000 - 10FFFF ║ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
 

 

  UTF-8的特點是對不同範圍的字元使用不同長度的編碼。對於0x00-0x7F之間的字元,UTF-8編碼與ASCII編碼完全相同。UTF-8編碼的最大長度是4個位元組。從上表可以看出,4位元組模板有21個x,即可以容納21位位元字。Unicode的最大碼位0x10FFFF也只有21位。
 

 

  例1:“漢”字的Unicode編碼是0x6C49。0x6C49在0x0800-0xFFFF之間,使用用3位元組模板了:1110xxxx 10xxxxxx 10xxxxxx。將0x6C49寫成二進位是:0110 1100 0100 1001, 用這個位元流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。
 

 

  例2:Unicode編碼0x20C30在0x010000-0x10FFFF之間,使用用4位元組模板了:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。將0x20C30寫成21位位元字(不足21位就在前面補0):0 0010 0000 1100 0011 0000,用這個位元流依次代替模板中的x,得到:11110000 10100000 10110000 10110000,即F0 A0 B0 B0。
 

 

  UTF-16
 

 

  UTF-16編碼以16位不帶正負號的整數為單位。我們把Unicode編碼記作U。編碼規則如下:
 

 

  如果U<0x10000,U的UTF-16編碼就是U對應的16位不帶正負號的整數(為書寫簡便,下文將16位不帶正負號的整數記作WORD)。
 

 

  如果U≥0x10000,我們先計算U'=U-0x10000,然後將U'寫成二進位形式:yyyy yyyy yyxx xxxx xxxx,U的UTF-16編碼(二進位)就是:110110yyyyyyyyyy 110111xxxxxxxxxx。
 

 

  為什麼U'可以被寫成20個二進位位?Unicode的最大碼位是0x10ffff,減去0x10000後,U'的最大值是0xfffff,所以肯定可以用20個二進位位表示。例如:Unicode編碼0x20C30,減去0x10000後,得到0x10C30,寫成二進位是:0001 0000 1100 0011 0000。用前10位依次替代模板中的y,用後10位依次替代模板中的x,就得到:1101100001000011 1101110000110000,即0xD843 0xDC30。
 

 

  按照上述規則,Unicode編碼0x10000-0x10FFFF的UTF-16編碼有兩個WORD,第一個WORD的高6位是110110,第二個WORD的高6位是110111。可見,第一個WORD的取值範圍(二進位)是11011000 00000000到11011011 11111111,即0xD800-0xDBFF。第二個WORD的取值範圍(二進位)是11011100 00000000到11011111 11111111,即0xDC00-0xDFFF。
 

 

  為了將一個WORD的UTF-16編碼與兩個WORD的UTF-16編碼區分開來,Unicode編碼的設計者將0xD800-0xDFFF保留下來,並稱為代理區(Surrogate):
 

 

  D800-DB7F ║ High Surrogates ║ 高位替代
 

 

  DB80-DBFF ║ High Private Use Surrogates ║ 高位專用替代
 

 

  DC00-DFFF ║ Low Surrogates ║ 低位替代
 

 

  高位替代就是指這個範圍的碼位是兩個WORD的UTF-16編碼的第一個WORD。低位替代就是指這個範圍的碼位是兩個WORD的UTF-16編碼的第二個WORD。那麼,高位專用替代是什麼意思?我們來解答這個問題,順便看看怎麼由UTF-16編碼推導Unicode編碼。
 

 

  如果一個字元的UTF-16編碼的第一個WORD在0xDB80到0xDBFF之間,那麼它的Unicode編碼在什麼範圍內?我們知道第二個WORD的取值範圍是0xDC00-0xDFFF,所以這個字元的UTF-16編碼範圍應該是0xDB80 0xDC00到0xDBFF 0xDFFF。我們將這個範圍寫成二進位:
 

 

  1101101110000000 11011100 00000000 - 1101101111111111 1101111111111111
 

 

  按照編碼的相反步驟,取出高低WORD的後10位,並拼在一起,得到
 

 

  1110 0000 0000 0000 0000 - 1111 1111 1111 1111 1111
 

 

  即0xe0000-0xfffff,按照編碼的相反步驟再加上0x10000,得到0xf0000-0x10ffff。這就是UTF-16編碼的第一個WORD在0xdb80到0xdbff之間的Unicode編碼範圍,即平面15和平面16。因為Unicode標準將平面15和平面16都作為專用區,所以0xDB80到0xDBFF之間的保留碼位被稱作高位專用替代。
 

 

  UTF-32
 

 

  UTF-32編碼以32位不帶正負號的整數為單位。Unicode的UTF-32編碼就是其對應的32位不帶正負號的整數。
 

 

  位元組序
 

 

  根據位元組序的不同,UTF-16可以被實現為UTF-16LE或UTF-16BE,UTF-32可以被實現為UTF-32LE或UTF-32BE。例如:
 

 

  Unicode編碼 ║ UTF-16LE ║ UTF-16BE ║ UTF32-LE ║ UTF32-BE
 

 

  0x006C49 ║ 49 6C ║ 6C 49 ║ 49 6C 00 00 ║ 00 00 6C 49
 

 

  0x020C30 ║ 43 D8 30 DC ║ D8 43 DC 30 ║ 30 0C 02 00 ║ 00 02 0C 30
 

 

  那麼,怎麼判斷位元組流的位元組序呢?Unicode標準建議用BOM(Byte Order Mark)來區分位元組序,即在傳輸位元組流前,先傳輸被作為BOM的字元"零寬無中斷空格"。這個字元的編碼是FEFF,而反過來的FFFE(UTF-16)和FFFE0000(UTF-32)在Unicode中都是未定義的碼位,不應該出現在實際傳輸中。下表是各種UTF編碼的BOM:
 

 

  UTF編碼 ║ Byte Order Mark
 

 

  UTF-8 ║ EF BB BF
 

 

  UTF-16LE ║ FF FE
 

 

  UTF-16BE ║ FE FF
 

 

  UTF-32LE ║ FF FE 00 00
 

 

  UTF-32BE ║ 00 00 FE FF

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.