程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Ansi,UTF8,Unicode編碼

Ansi,UTF8,Unicode編碼

編輯:C++入門知識

最近在寫網絡數據傳輸的程序,被各種編碼搞的一塌糊塗,在這裡簡單記錄如下:

字符內碼(charcter code)指的是用來代表字符的內碼.讀者在輸入和存儲文檔時都要使用內碼,內碼分為
a.單字節內碼 -- Single-Byte character sets (SBCS),可以支持256個字符編碼.
b.雙字節內碼 -- Double-Byte character sets (DBCS),可以支持65000個字符編碼.
前者即為ASCII編碼,後者對應ANSI。在簡體中文的操作系統中ANSI就指的是GB2312,代碼頁936(ANSI下不同語言有不同的代碼頁)。

GB2312是對 ANSI 的簡體中文擴展。GB2312共收錄了七千個字符,由於GB2312支持的漢字太少而且不支持繁體中文,所以GBK對GB2312進行了擴展,以支持繁體中文和更多的字符,GBK共支持大概22000個字符,GB18030是在GBK的基礎上又增加了藏文、蒙文、維吾爾文等主要的少數民族文字。

ANSI有很多代碼頁,使用不同代碼頁的內碼無法在其他代碼頁平台上正常顯示。由於各國之間的編碼不同造成的交流傳輸不便,ISO 打算廢除所有的地區性編碼方案,重新建立一個全球性的編碼方案把所有字母和符號都統一編碼進去,稱之為 "Universal Multiple-Octet Coded Character Set",簡稱為 UCS(ISO10646)。同時又有unicode.org這個組織也制定了自己的全球性編碼 unicode,自從unicode2.0開始,unicode采用了與USC相同的字庫和字碼,階段主要采用的是 UCS-2/unicode 16 位的編碼。

UTF(Unicode/UCS Transfer Format),UCS 變長存儲的編碼方式,主要用來解決 UCS 編碼的傳輸問題的。分為 UTF-7,UTF-8,UTF-16,UTF-32 等。UTF-8是一次傳輸8位(一個字節)的UTF編碼方式,一個字符可能會經過1-6次傳輸,具體的跟 unicode/UCS 之間的轉換關系如下:

unicode(U+) utf-8 xxxxxxx xxxxx10xxxxxx xxxx10xxxxxx10xxxxxx U+00010000 - U+001FFFFF: 11110xxx10xxxxxx10xxxxxx10xxxxxx U+00200000 - U+03FFFFFF: 111110xx10xxxxxx10xxxxxx10xxxxxx10xxxxxx U+04000000 - U+7FFFFFFF: 1111110x10xxxxxx10xxxxxx10xxxxxx10xxxxxx10xxxxxx

比如: "我" 的unicode/UCS編碼為 "U+6211"(01100010 00010001),在U+00000800 - U+0000FFFF之間,所以采用三字節編碼,按規則分段為:0110 001000 010001,再分別替換上表中的x,得到11100110 10001000 10010001,即為 "E6 88 91",這就是 "我" 的UTF-8編碼。
舉個有趣的例子:
在 Windows 的記事本裡新建一個文本文件,輸入"聯通"兩個字,保存,關閉,再次打開,會發現文本已經不是"聯通"了,而是幾個亂碼。
當使用記事本新建文件時,默認的編碼是 ANSI,輸入中文就是 GB 系列的編碼,"聯通" 兩字的編碼為:
c1 1100 0001
aa 1010 1010
cd 1100 1101
a8 1010 1000
注意到了嗎?第一二個字節、第三四個字節的起始部分的都是 "110" 和 "10",正好與 UTF-8 規則裡的兩字節模板是一致的,於是再次打開記事本時,記事本就誤認為這是一個UTF-8編碼的文件,讓我們把第一個字節的110和第二個字節的10去掉,我們就得到了"00001 101010",再把各位對齊,補上前導的0,就得到了 "0000 0000 0110 1010",這是 UNICODE 的 006A,也就是小寫的字母 "j",而之後的兩字節用 UTF-8 解碼之後是0368,這個字符什麼也不是。這就是只有 "聯通" 兩個字的文件沒有辦法在記事本裡正常顯示的原因。
而如果你在 "聯通" 之後多輸入幾個其他字,其他的字的編碼不見得又恰好是 110 和 10 開始的字節,這樣再次打開時,記事本就不會堅持這是一個 UTF-8 編碼的文件,而會用 ANSI 的方式解讀之,這時亂碼又不出現了。

UTF-16是一次傳輸兩個字節的UTF編碼方式,現如今Unicode/UCS也主要采用16位編碼,所以UTF-16的存儲方式和Unicode/UCS的編碼方式也相同。確切的。

在UTF-16或者UCS的編碼中經常遇到這兩個選項,big endian 和little endian 是CPU處理多字節數的不同方式。例如“漢”字的 Unicode/UCS 編碼是 6C49。那麼寫到文件裡時,究竟是將 6C 寫在前面,還是將 49 寫在前面?如果將 6C 寫在前面,就是big endian。還是將 49 寫在前面,就是little endian。
BOM 稱為 "Byte Order Mark"。UTF-8 以字節為編碼單元,沒有字節序的問題。而 UTF-16 以兩個字節為編碼單元,在解釋一個 UTF-16 文本前,首先要弄清楚每個編碼單元的字節序。例如收到一個 "奎" 的 Unicode/UCS 編碼是 594E,"乙" 的 Unicode/UCS 編碼是 4E59。如果我們收到 UTF-16 字節流 "594E",那麼這是 "奎" 還是 "乙"?
在Unicode/UCS編碼中有一個叫做 "ZERO WIDTH NO-BREAK SPACE" 的字符,它的編碼是FEFF。而FFFE在Unicode/UCS中是不存在的字符,所以不應該出現在實際傳輸中。UCS規范建議我們在傳輸字節流前,先傳輸字符 "ZERO WIDTH NO-BREAK SPACE"。這樣 的。因此字符 "ZERO WIDTH NO-BREAK SPACE" 又被稱作 BOM。
UTF-8 不需要 BOM 來表明字節順序,但可以用 BOM 來表明編碼方式。字符 "ZERO WIDTH NO-BREAK SPACE" 的 UTF-8 編碼是 EF BB BF。所以如果接收者收到以 EF BB BF 開頭的字節流,就知道這是 UTF-8 編碼了。Windows 就是使用 BOM 來標記文本文件的編碼方式的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved