計算機編碼,unicode、gb等的理解
- 本文參考:
https://www.cnblogs.com/gavin-num1/p/5170247.html
https://blog.csdn.net/iefreer/article/details/4836844
http://www.fmddlmyy.cn/text6.html
- 前述
最早接觸的編碼是ASCII,後來常用到的有GB2312、GBK、UTF-8。沒有深入瞭解過各種編碼,糊里糊塗的一直在用UTF-8,每次專案開始啟動的時候會要求專案組成員配置IDE為UTF-8,也還好,基本沒有碰到什麼問題。
推薦連結,配置IDE編碼為UTF-8:https://www.aliyun.com/jiaocheng/845302.html?spm=5176.100033.2.28.378d18f7wrpYDv
之前信誓旦旦的說“一個位元組是8位,一個漢字是兩個位元組十六位”,一個位元組8位是對的,但是一個漢字可不一定是兩個位元組。那一個漢字幾個位元組呢?要看哪一種編碼,一般GB系列編碼下是兩個位元組,UTF-8編碼下是三個位元組。可以寫一個簡單的main方法測試一下。
public static void main(String[] args) throws UnsupportedEncodingException { // 測試各種編碼下漢字“一”佔幾個位元組 System.out.println(new String("一").getBytes("GBK").length); System.out.println(new String("一").getBytes("GB2312").length); System.out.println(new String("一").getBytes("UTF-8").length); System.out.println(new String("一").getBytes("UTF-16").length); System.out.println(new String("一").getBytes("UTF-32").length); }
執行結果:
2 2 3 4 4
可以看到,GBK、GB2312編碼下漢字“一”佔用2個位元組,UTF-8編碼下佔用3個位元組,UTF-16、UTF-32編碼下佔用4個位元組。所以,在談論一個字元佔用幾個位元組時,不能脫離具體編碼。
- 組織
(1) 國際標準化組織(ISO),為各行各業指定標準化規範,其中包括“通用字符集”(Universal Character Set,簡稱UCS),比較出名的是ISO-8859-1。
(2) 統一碼聯盟,制定了一種可以對全球幾乎所有語言文字進行編碼的標準,並且開發了Unicode標準(The Unicode Standard)。
- ASCII
/*
* ASCII(American Standard Code for Information Interchange,美國資訊互換標準程式碼,ASCⅡ)是基於拉丁字母的一套電腦編碼系統。
* 它主要用於顯示現代英語和其他西歐語言。它是現今最通用的單位元組編碼系統,並等同於國際標準ISO/IEC 646。 * ASCII第一次以規範標準的型態發表是在1967年,最後一次更新則是在1986年,至今為止共定義了128個字元,其中33個字元無法顯示(這是以現今
* 作業系統為依歸,但在DOS模式下可顯示出一些諸如笑臉、撲克牌花式等8-bit符號),且這33個字元多數都已是陳廢的控制字元,控制字元的用途主要是
* 用來操控已經處理過的文字,在33個字元之外的是95個可顯示的字元,包含用鍵盤敲下空白鍵所產生的空白字元也算1個可顯示字元(顯示為空白)。
* 引用自: http://ascii.911cha.com/
*/
1個位元組8位,位有兩種狀態0和1,所以1個位元組能夠有2^8種狀態,也就是256種狀態。從0000000到11111111。
“上個世紀60年代,美國製定了一套字元編碼,對英語字元與二進位制位之間的關係,做了統一規定。這被稱為ASCII碼,一直沿用至今。
ASCII碼一共規定了128個字元的編碼,比如空格“SPACE”是32(二進位制00100000),大寫的字母A是65(二進位制01000001)。這128個符號(包括32個不能打印出來的控制符號),只佔用了一個位元組的後面7位,最前面的1位統一規定為0。”
- ISO-8859-1
- ANSI
ANSI是預設的編碼方式。對於英文檔案是ASCII編碼,對於簡體中文檔案是GB2312編碼(只針對Windows簡體中文版,如果是繁體中文版會採用Big5碼)。
ANSI是在ASCII的基礎上的擴充套件。
- GB2312/GBK
這就是漢字的國標碼,專門用來表示漢字,是雙位元組編碼,而英文字母和ISO-8859-1一致(相容ISO-8859-1編碼)。其中GBK編碼能夠用來同時表示繁體字和簡體字,而GB2312只能表示簡體字,GBK是相容GB2312編碼的。
- Big5
又稱為大五碼或五大碼,是使用繁體中文(正體中文)社群中最常用的電腦漢字字符集標準,共收錄13,060個漢字。主要用於臺灣。
- UCS/Unicode
UCS是Unicode的簡稱,根據維基百科全書(http://zh.wikipedia.org/wiki/)的記載:歷史上存在兩個試圖獨立設計Unicode的組織,即國際標準化組織(ISO)和統一碼聯盟。ISO開發了ISO 10646專案,Unicode協會開發了Unicode專案。
UCS只是規定如何編碼,並沒有規定如何傳輸、儲存這個編碼。例如“漢”字的UCS編碼是6C49,我可以用4個ascii數字來傳輸、儲存這個編碼;也可以用utf-8編碼:3個連續的位元組E6 B1 89來表示它。關鍵在於通訊雙方都要認可。UTF-8、UTF-7、UTF-16都是被廣泛接受的方案。UTF-8的一個特別的好處是它與ISO-8859-1完全相容。UTF是“UCS Transformation Format”的縮寫。
- UTF-8
UTF-8就是以8位為單元對UCS進行編碼。從UCS-2到UTF-8的編碼方式如下:
UCS-2編碼(16進位制) | UTF-8 位元組流(二進位制) |
0000 - 007F | 0xxxxxxx |
0080 - 07FF | 110xxxxx 10xxxxxx |
0800 - FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
例如“漢”字的Unicode編碼是6C49。6C49在0800-FFFF之間,所以肯定要用3位元組模板了:1110xxxx 10xxxxxx 10xxxxxx。將6C49寫成二進位制是:0110 110001 001001, 用這個位元流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。
讀者可以用記事本測試一下我們的編碼是否正確。需要注意,UltraEdit在開啟utf-8編碼的文字檔案時會自動轉換為UTF-16,可能產生混淆。你可以在設定中關掉這個選項。更好的工具是Hex Workshop。
UTF-16以16位為單元對UCS進行編碼。對於小於0x10000的UCS碼,UTF-16編碼就等於UCS碼對應的16位無符號整數。對於不小於0x10000的UCS碼,定義了一個演算法。不過由於實際使用的UCS2,或者UCS4的BMP必然小於0x10000,所以就目前而言,可以認為UTF-16和UCS-2基本相同。但UCS-2只是一個編碼方案,UTF-16卻要用於實際的傳輸,所以就不得不考慮位元組序的問題。
-
UTF的位元組序和BOM
UTF-8以位元組為編碼單元,沒有位元組序的問題。UTF-16以兩個位元組為編碼單元,在解釋一個UTF-16文字前,首先要弄清楚每個編碼單元的位元組序。例如“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16位元組流“594E”,那麼這是“奎”還是“乙”?
Unicode規範中推薦的標記位元組順序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一個有點小聰明的想法:
在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"的字元,它的編碼是FEFF。而FFFE在UCS中是不存在的字元,所以不應該出現在實際傳輸中。UCS規範建議我們在傳輸位元組流前,先傳輸字元"ZERO WIDTH NO-BREAK SPACE"。
這樣如果接收者收到FEFF,就表明這個位元組流是Big-Endian的;如果收到FFFE,就表明這個位元組流是Little-Endian的。因此字元"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來標記文字檔案的編碼方式的。