[概述]
????? 計算機中的一切都是以數字來表示的,字符同樣如此。字符編碼就是將字符集編碼成為數字序列,以便能讓計算機識別。各個地區和國家使用的語言有別,將本地使用的語言符號進行編碼就得到本地編碼字符集。例如西歐國家使用的本地編碼是ISO8859-1,中國大陸和新加坡等地區使用本地編碼是GB2312或GBK,中國港臺地區使用的本地編碼是BIG5,韓國和日本的本地編碼分別是euc-kr和Shift_JIS。電腦的操作系統支持各種本地編碼字符集,操作系統默認的本地編碼和你所安裝的操作系統語言版本是一致的。本地集只對本地使用的文字符號進行了編碼,并不包括其他地區使用的文字,即使兩個本地集中包含了相同的字符,這個字符的編碼值也是不同的。例如“中”的GB2312或GBK編碼值為“0xD6D0”,而BIG5編碼值為“0xA4A4”。
????? 全球信息交流與融合的趨勢要求實現對本地字符集的統一,1984年4月ISO成立了工作組,針對各國文字、符號進行統一編碼,這種編碼成為Unicode。Unicode于1992年6月通過DIS(DrafInternationalStandard),V2.0版本于1996年發布。Unicode編碼包括了符號6811個、漢字20902個、韓文11172個、等等。Unicode雖然實現了全球統一編碼,但是在字符集數量和編碼效率方面顯然存在著不足,而UTF-8、UTF-16就是針對Unicode編碼進行轉換或擴充形成的編碼,UTF是Unicode Translation Format的縮寫。
????? 計算機中的一切都是以數字來表示的,字符同樣如此。字符編碼就是將字符集編碼成為數字序列,以便能讓計算機識別。各個地區和國家使用的語言有別,將本地使用的語言符號進行編碼就得到本地編碼字符集。例如西歐國家使用的本地編碼是ISO8859-1,中國大陸和新加坡等地區使用本地編碼是GB2312或GBK,中國港臺地區使用的本地編碼是BIG5,韓國和日本的本地編碼分別是euc-kr和Shift_JIS。電腦的操作系統支持各種本地編碼字符集,操作系統默認的本地編碼和你所安裝的操作系統語言版本是一致的。本地集只對本地使用的文字符號進行了編碼,并不包括其他地區使用的文字,即使兩個本地集中包含了相同的字符,這個字符的編碼值也是不同的。例如“中”的GB2312或GBK編碼值為“0xD6D0”,而BIG5編碼值為“0xA4A4”。
????? 全球信息交流與融合的趨勢要求實現對本地字符集的統一,1984年4月ISO成立了工作組,針對各國文字、符號進行統一編碼,這種編碼成為Unicode。Unicode于1992年6月通過DIS(DrafInternationalStandard),V2.0版本于1996年發布。Unicode編碼包括了符號6811個、漢字20902個、韓文11172個、等等。Unicode雖然實現了全球統一編碼,但是在字符集數量和編碼效率方面顯然存在著不足,而UTF-8、UTF-16就是針對Unicode編碼進行轉換或擴充形成的編碼,UTF是Unicode Translation Format的縮寫。
?
[細節]
關于ASCII編碼
????? ASCII編碼是美國標準信息交換碼,這種編碼方式針對的是英文字符。ASCII編碼使用一個字節對字符進行編碼,而且字節的最高位都為0,因此ASCII編碼的字符集大小是128個。由于英文字母僅有26個,再加上其他一些常用符號,總大小也不會超過128個,因此ASCII編碼的空間是足夠的。例如,字符“a”被編碼為0x61,字符“b”被編碼為0x62等等。注意,在有的時候ASCII泛指本地編碼,例如文本編輯器UltraEdit中有諸如“ASCII轉Unicode”的功能,這里的ASCII就泛指本地編碼,如果本地編碼是GBK,這個功能執行的就是GBK編碼到Unicode編碼的轉換。
關于ASCII編碼
????? ASCII編碼是美國標準信息交換碼,這種編碼方式針對的是英文字符。ASCII編碼使用一個字節對字符進行編碼,而且字節的最高位都為0,因此ASCII編碼的字符集大小是128個。由于英文字母僅有26個,再加上其他一些常用符號,總大小也不會超過128個,因此ASCII編碼的空間是足夠的。例如,字符“a”被編碼為0x61,字符“b”被編碼為0x62等等。注意,在有的時候ASCII泛指本地編碼,例如文本編輯器UltraEdit中有諸如“ASCII轉Unicode”的功能,這里的ASCII就泛指本地編碼,如果本地編碼是GBK,這個功能執行的就是GBK編碼到Unicode編碼的轉換。
?
關于ISO8859-1編碼
????? ISO8859-1是西歐語系國家通用的字符集編碼,ISO8859-1使用一個字節對字符進行編碼,編碼值范圍是0x00-0xFF。其中,0x00-0x1F用作控制字,0x20-0x7F表示字母、數字和符號這些圖形字符,0xA0-0xFF作為附加部分使用。由于ASCII編碼只使用了一個字節中的低7位,編碼范圍僅為0-127,雖然可以容納英文字符和其他的一些符號,但是卻不能包含除英文以外的其他西歐語言的字母,因此ASCII編碼在西歐國家并不通用。針對這個問題ISO在ASCII編碼的基礎上進行了擴充,制定了ISO8859-1編碼,ISO8859-1編碼使用了一個字節的全部8位,編碼范圍是0-255,能包含西歐語系的所有字母和符號。
????? ISO8859-1是西歐語系國家通用的字符集編碼,ISO8859-1使用一個字節對字符進行編碼,編碼值范圍是0x00-0xFF。其中,0x00-0x1F用作控制字,0x20-0x7F表示字母、數字和符號這些圖形字符,0xA0-0xFF作為附加部分使用。由于ASCII編碼只使用了一個字節中的低7位,編碼范圍僅為0-127,雖然可以容納英文字符和其他的一些符號,但是卻不能包含除英文以外的其他西歐語言的字母,因此ASCII編碼在西歐國家并不通用。針對這個問題ISO在ASCII編碼的基礎上進行了擴充,制定了ISO8859-1編碼,ISO8859-1編碼使用了一個字節的全部8位,編碼范圍是0-255,能包含西歐語系的所有字母和符號。
?
關于GB2312、GBK和BIG5編碼
????? GB2312碼是中華人民共和國國家漢字信息交換使用碼,全稱《信息交換使用漢字編碼字符集-基本集》,由國家標準總局發布,1981年5月1日實施,中國大陸和新加坡等地使用此編碼。GB2312收錄了簡化漢字、符號、字母、日文假名等共計7445個字符,其中漢字占6763個。GB2312將代碼表分區94個區(0xA1-0xFE),對應第一個字節,每個區94個位(0xA1-0xFE),對應了第二字節,兩個字節的值分別為區號的值和位號的值加32(0x20),因此也被稱為區位碼。GB2312的編碼范7圍是0x2121-0x777E,與ASCII有重疊,通常方法是將GB碼的兩個字節的最高位置1區別。
????? GBK是GB2312-80的擴展,向上兼容,包含了20902個漢字,編碼范圍是0x8140-0xFEFE,剔除高位0x80的字位,其他字符都可以一一映射到Unicode2.0。GB18030-2000(GBK2K)在GBK的基礎上增加了藏、蒙等少數民族的字符,GBK2K從根本上解決了字位不夠、字形不足的問題。GBK2K首先要求實現能夠完全映射到Unicode3.0標準的所有字形,現在還沒有任何一個操作系統支持GBK2K。
??????BIG5碼被稱為大五碼,是中國港臺地區使用的字符編碼方式。TW-BIG5碼將所有字分為兩大群,即常用字區和次常用字區,每個字區分都采用筆畫排序,同筆畫的字依部首排序。TW-BIG5每個字由兩個字節組成,第一個字節編碼范圍是0xA1-0xF9,第二個字節編碼范圍是0x40-0x7E和0xA1-0xFE,共計收入13868個字,其中包括5401個常用字、7652個次常用字、7個擴充字、以及808個其他符號。
????? GB2312碼是中華人民共和國國家漢字信息交換使用碼,全稱《信息交換使用漢字編碼字符集-基本集》,由國家標準總局發布,1981年5月1日實施,中國大陸和新加坡等地使用此編碼。GB2312收錄了簡化漢字、符號、字母、日文假名等共計7445個字符,其中漢字占6763個。GB2312將代碼表分區94個區(0xA1-0xFE),對應第一個字節,每個區94個位(0xA1-0xFE),對應了第二字節,兩個字節的值分別為區號的值和位號的值加32(0x20),因此也被稱為區位碼。GB2312的編碼范7圍是0x2121-0x777E,與ASCII有重疊,通常方法是將GB碼的兩個字節的最高位置1區別。
????? GBK是GB2312-80的擴展,向上兼容,包含了20902個漢字,編碼范圍是0x8140-0xFEFE,剔除高位0x80的字位,其他字符都可以一一映射到Unicode2.0。GB18030-2000(GBK2K)在GBK的基礎上增加了藏、蒙等少數民族的字符,GBK2K從根本上解決了字位不夠、字形不足的問題。GBK2K首先要求實現能夠完全映射到Unicode3.0標準的所有字形,現在還沒有任何一個操作系統支持GBK2K。
??????BIG5碼被稱為大五碼,是中國港臺地區使用的字符編碼方式。TW-BIG5碼將所有字分為兩大群,即常用字區和次常用字區,每個字區分都采用筆畫排序,同筆畫的字依部首排序。TW-BIG5每個字由兩個字節組成,第一個字節編碼范圍是0xA1-0xF9,第二個字節編碼范圍是0x40-0x7E和0xA1-0xFE,共計收入13868個字,其中包括5401個常用字、7652個次常用字、7個擴充字、以及808個其他符號。
?
關于Unicode編碼
????? ISO(國際化標準組織)將全世界所有的符號進行統一編碼,稱為Unicode編碼。Unicode編碼的字符占用兩個字符的大小,對于ASCII碼表示的字符,Unicode只是簡單的在ASCII碼原來的一個字節碼值上增加一個所有位全為0的字節。Unicode使用兩個字節編碼,因此能表示的字符集最大為65536,另外Unicode中還保留兩千多個數值未用于字符編碼。由于Unicode編碼的空間有限,只能包含各個地區常用的字符而非所有字符,因此,在相當長的一段時間里,本地化字符編碼和Unicode編碼將共存。
????? ISO(國際化標準組織)將全世界所有的符號進行統一編碼,稱為Unicode編碼。Unicode編碼的字符占用兩個字符的大小,對于ASCII碼表示的字符,Unicode只是簡單的在ASCII碼原來的一個字節碼值上增加一個所有位全為0的字節。Unicode使用兩個字節編碼,因此能表示的字符集最大為65536,另外Unicode中還保留兩千多個數值未用于字符編碼。由于Unicode編碼的空間有限,只能包含各個地區常用的字符而非所有字符,因此,在相當長的一段時間里,本地化字符編碼和Unicode編碼將共存。
?
關于UTF-8和UTF-16編碼
????? UTF-8和UTF-16編碼仍然屬于Unicode編碼,它們是在Unicode編碼基礎上進行了轉換或擴展。例如在Windows XP和2000操作系統中,Unicode編碼指的就是UTF-16編碼。
????? UTF-8編碼是將Unicode編碼中不同范圍的字符采用不同的字節進行編碼,對于ASCII編碼的字符仍使用一個字節進行編碼,UTF-8編碼完全兼容ASCII編碼。與Unicode想比較,UTF-8編碼使得英文文檔的占用空間減小了一半,因此UTF-8頗受英語系國家的青睞。除此之外,UTF-8編碼中不會出現值為0x0000的數據,這樣避免了和某些程序語言產生沖突,而UTF-8編碼的補充位使得數據能夠被方便的檢測出傳輸過程中是否發生錯誤。通常,UTF-8編碼都使用“EF BB BF”三個字節數據作為文件開頭。
????? UTF-8和UTF-16編碼仍然屬于Unicode編碼,它們是在Unicode編碼基礎上進行了轉換或擴展。例如在Windows XP和2000操作系統中,Unicode編碼指的就是UTF-16編碼。
????? UTF-8編碼是將Unicode編碼中不同范圍的字符采用不同的字節進行編碼,對于ASCII編碼的字符仍使用一個字節進行編碼,UTF-8編碼完全兼容ASCII編碼。與Unicode想比較,UTF-8編碼使得英文文檔的占用空間減小了一半,因此UTF-8頗受英語系國家的青睞。除此之外,UTF-8編碼中不會出現值為0x0000的數據,這樣避免了和某些程序語言產生沖突,而UTF-8編碼的補充位使得數據能夠被方便的檢測出傳輸過程中是否發生錯誤。通常,UTF-8編碼都使用“EF BB BF”三個字節數據作為文件開頭。
????? Unicode編碼和UTF-8編碼結構的對應關系如下:
??????? Unicode編碼值???????????????????????? UTF-8編碼結構
????? ? \u0001 - \u007E??????????????????????0XXXXXXX
????? ? \u0080 - \u07FF 和 \u0000???????110XXXXX 10XXXXXX
??????? \u0800 - \uFFFF??????????????????????1110XXXX 10XXXXXX 10XXXXXX
?
????? Unicode編碼與UTF-8編碼的轉換如下(U8代表UTF-8編碼,U代表Unicode編碼):
????? 1) 位于Unicode編碼空間 \u0001-\u007F之間的字符(即編碼使用位小于8位的字符),UTF-8采用一個字節對這些字符進行編碼。直接將Unicode編碼的低位取出就得到了UTF-8編碼。轉換過程可表示為:U8 = (byte)U。
????? 2) 位于Unicode編碼空間\u0080-\u07FF之間的字符以及\u0000表示的字符(即編碼使用位為8-11位的字符,以及空字符),UTF-8采用兩個字節對這些字符進行編碼。這時候,將Unicode編碼轉換為UTF-8編碼的方法是:將Unicode編碼的低6位取出,在前面補充“10”作為低字節;將7-11位取出,在前面補充“110”作為高字節。轉換過程可表示為:U8 = [(byte)(0xC0 | (0x01F & (U>>6)),(byte)(0x80 | (0x3F & U)]。
????? 3) 位于Unicode編碼空間\u080-\uFFFF之間的字符(即編碼使用位為12-16位的字符),UTF-8采用三個字節對這些字符進行編碼。這時候,將Unicode編碼轉換為UTF-8編碼的方法是:將Unicode編碼的低6位取出,在前面補充“10”作為低字節;將7-12位取出,在前面補充“10”作為中字節;將13-16位取出,在前面補充“1110”作為高字節。轉換過程可表示為:U8 = [(byte)(0xE0 | (0x0F & (U>>12))),(byte)(0x80 | (0x03F & (U>>6)),(byte)(0x80 | (0x3F & U)]。
????? 1) 位于Unicode編碼空間 \u0001-\u007F之間的字符(即編碼使用位小于8位的字符),UTF-8采用一個字節對這些字符進行編碼。直接將Unicode編碼的低位取出就得到了UTF-8編碼。轉換過程可表示為:U8 = (byte)U。
????? 2) 位于Unicode編碼空間\u0080-\u07FF之間的字符以及\u0000表示的字符(即編碼使用位為8-11位的字符,以及空字符),UTF-8采用兩個字節對這些字符進行編碼。這時候,將Unicode編碼轉換為UTF-8編碼的方法是:將Unicode編碼的低6位取出,在前面補充“10”作為低字節;將7-11位取出,在前面補充“110”作為高字節。轉換過程可表示為:U8 = [(byte)(0xC0 | (0x01F & (U>>6)),(byte)(0x80 | (0x3F & U)]。
????? 3) 位于Unicode編碼空間\u080-\uFFFF之間的字符(即編碼使用位為12-16位的字符),UTF-8采用三個字節對這些字符進行編碼。這時候,將Unicode編碼轉換為UTF-8編碼的方法是:將Unicode編碼的低6位取出,在前面補充“10”作為低字節;將7-12位取出,在前面補充“10”作為中字節;將13-16位取出,在前面補充“1110”作為高字節。轉換過程可表示為:U8 = [(byte)(0xE0 | (0x0F & (U>>12))),(byte)(0x80 | (0x03F & (U>>6)),(byte)(0x80 | (0x3F & U)]。
?
????? UTF-16編碼在Unicode基礎上進行了一些細節上的擴充,增加了對Unicode編碼沒有包括的字符的表示方式。UTF-16對Unicode的擴充并沒有影響Unicode編碼中的原有字符,容易看出Unicode是UTF-16的子集。Unicode編碼將0xD800-0xDFFF區間的數值保留,被稱為代理區間,區間共包含2048個數值,其中0xD800-0xD6FF是高半代理區,0xDC00-0xDFFF是低半代理區。UTF-16編碼就是在Unicode編碼基礎上利用代理區擴充字符編碼的機制。UTF-16編碼從兩個區域分別取一個編碼,組成一個4字節的代理對來表示一個編碼字符,就能夠在Unicode基礎上擴充了1024*1024個字符。UTF-16足夠用來編碼全球的所有字符,微軟從Windows2000開始支持UTF-16編碼。
?
關于Little-Endian和Big-Endian
????? 在不同體系的計算機系統中,編碼的Unicode字符在內存中存儲的順序是不同的。使用Inter生產的CPU的計算機,內存中數據存儲通常是低字節在前,高字節在后,這種存儲方式被稱為Little-Endian。在對于一些計算機,內存中數據存儲通常是高字節在前,低字節在后,這種存儲方式被稱為Big-Endian。
????? UTF-16編碼的文件通常在文件開頭用字符標志出使用的存儲方式:若文件開頭是“0xFF 0xFF”,表示文件其余部分是Little-Endian的 UTF-16編碼;若文件開頭是“0xFE 0xFF”,表示文件其余部分是Big-Endian的 UTF-16編碼。
????? 在不同體系的計算機系統中,編碼的Unicode字符在內存中存儲的順序是不同的。使用Inter生產的CPU的計算機,內存中數據存儲通常是低字節在前,高字節在后,這種存儲方式被稱為Little-Endian。在對于一些計算機,內存中數據存儲通常是高字節在前,低字節在后,這種存儲方式被稱為Big-Endian。
????? UTF-16編碼的文件通常在文件開頭用字符標志出使用的存儲方式:若文件開頭是“0xFF 0xFF”,表示文件其余部分是Little-Endian的 UTF-16編碼;若文件開頭是“0xFE 0xFF”,表示文件其余部分是Big-Endian的 UTF-16編碼。