在網絡傳輸的過程當中,常常會使用UTF-8編碼,以免亂碼的問題。另外,咱們使用文本編輯器編輯文件的時候,也能夠選擇諸如ANSI、Unicode、UTF-8等多種編碼方式。那麼,各類編碼方式之間有什麼區別呢?html
對於計算機來講,全部的文件都是以二進制的格式存儲的。所謂編碼,就是將二進制位映射到字符集的過程。計算機最先起源於美國,當時他們制定了一套字符編碼,將英語字符到二進制位之間的關係,作了統一規定,稱爲 ASCII碼。ASCII碼規定,0x20(十進制32)如下的字節碼稱爲「控制字符」,分別規定了特殊的用途;0x20到0x7F的字符稱爲「打印字符」。ASCII編碼只使用一個字節的低7位。算法
ASCII碼錶:網絡
ASCII碼只能用來編碼英文字符,各個國家爲了表示他們本身的字符,分別擴展了ASCII碼。編輯器
歐洲碼錶,單字節編碼,包含一系列標準,如:ISO8859-1(西歐字符集)、ISO8859-2(東歐字符集)等編碼
編碼規則:spa
- 與 ASCII 相容,全部的低位皆不使用
- 高位中的前 32 個碼位 (0x80 -- 0x9F 或 128--159),保留給擴充定義的 32 個控制碼,稱爲 C1 控制碼 (0--31 稱爲 C0 控制碼)
- 高位中第 33 個碼位 (0xA0 或 160),也就是對應 ASCII 中 SP (空格) 的碼位,老是表明 Non-breakable space,也就是不許許折行的空格
- 每一個字符集定義至多 95 個字符,其碼位都在 0xA1 -- 0xFF 或 161--255
- 每一個字符集收錄歐洲某地區的共同經常使用字符,如:ISO8859-1
漢字編碼GB23十二、GBK和GB18030,擴展了ASCII碼的高位字節,並使用兩個字節來進行編碼。從ASCII、GB23十二、GBK到GB18030,這些編碼方式是向下兼容的,可是不一樣國家之間的字符編碼各不相同。爲了統一字符編碼,ISO (國際標準化組織)發佈了俗稱「UNICODE」的編碼規範。.net
Unicode的學名是「Universal Multiple-Octet Coded Character Set」,簡稱爲UCS,UCS能夠看做是"Unicode Character Set"的縮寫。code
UCS有兩種格式:UCS-2(兩個字節編碼)和UCS-4(四個字節編碼),其中UCS-4實際上只用了31位,最高位必須爲0。htm
UCS-4根據最高位爲0的最高字節分紅2^7=128個group,每一個group再根據次高字節分爲256個plane,每一個plane根據第3個字節分爲256行 (rows),每行包含256列(cells)。blog
group[0]的plane[0]被稱爲「Basic Multilingual Plane」,即BMP。也就是說UCS-4中高兩位字節爲0的碼位被稱做BMP,即:將UCS-4的BMP去掉前面的兩個零字節就獲得了UCS-2。在UCS-2的兩個字節前加上兩個零字節,就獲得了UCS-4的BMP。而目前的UCS-4規範中尚未任何字符被分配在BMP以外。
除了ASCII編碼以外,Unicode在制訂時沒有考慮與任何一種現有的編碼方案保持兼容,所以GBK與Unicode在漢字的內碼編排上徹底是不同的。
Unicode只是規定了字符的編碼方式,UTF-8(UTF-16)是實現Unicode的一種用於傳輸的編碼規範。UTF-8編碼規則
- 使用單字節編碼,字節的第一位爲0,後面7位爲這個符號的Unicode碼。所以對於英文字符,UTF-8編碼和ASCII碼是相同的
- 使用n字節編碼,第一個字節的前n位都爲1,第(n+1)位爲0,後面(n-1)字節的前兩位都爲「10」
UCS-2與UTF-8編碼對照:
UCS-2編碼(16進制) | UTF-8編碼(二進制) |
---|---|
0000 - 007F | 0xxxxxxx |
0080 - 07FF | 110xxxxx 10xxxxxx |
0800 - FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
UTF-16以16位爲單元對UCS進行編碼,對於小於0x10000的UCS碼,UTF-16編碼就等於UCS碼對應的16位無符號整數。對於不小於0x10000的UCS碼,定義了一個算法。因爲實際使用的UCS-2,或者UCS-4的BMP必然小於0x10000,所以能夠認爲UTF-16和UCS-2基本相同。但UCS-2只是一個編碼方案,UTF-16卻要用於實際的傳輸,因此就不得不考慮字節序的問題。
UTF-8以字節爲編碼單元,所以沒有字節序的問題;而UTF-16以兩個字節爲編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每一個編碼單元的字節序,即大端法(Big endian)仍是小端法(Little endian)。
Unicode規範中推薦的標記字節順序的方法是BOM(Byte Order Mark)。在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編碼是EFBBBF,因此若是接收者收到以EF BB BF開頭的字節流,就知道這是UTF-8編碼了。
BOM做爲一種標記方式,並非強制要求的
BOM | 編碼方式 |
---|---|
EF BB BF | UTF-8 |
FF FE | UTF-16/UCS-2, Little endian |
FE FF | UTF-16/UCS-2, Big endian |
FF FE 00 00 | UTF-32/UCS-4, Little endian |
00 00 FE FF | UTF-32/UCS-4, Big endian |
- utf8具備較好的容錯性; 從utf8字節流任何一個地方截斷均可以跳過非法的部分找到下一個字符的開頭,若是採用unicode編碼,從一個字的中間截斷會致使接下來全部的字符解析都是錯的,這在不可靠的網絡傳輸中是有利的
- utf8是變長的,對於經常使用字符,只使用一個字節編碼,能夠有效節省存儲空間或帶寬
Windows系統中,記事本的編碼默認是ANSI,表明系統默認編碼,在中文系統中通常是GB系列編碼。
與「標準」的區別:
- 「null」字符((char)0)用雙字節編碼,而不使用單字節,所以改進版的UTF-8格式不會直接出現null值
- 改進版的UTF-8只使用標準版UTF-8格式所定義的單字節、雙字節和三字節格式,JVM不能識別標準版UTF-8定義的四字節格式,而是使用自定義的兩個三字節格式來代替,且按照Big-Endian順序存儲
改進版UTF-8編碼方式:
字節數 | 位模式 | 碼點值 | 範圍 |
---|---|---|---|
單字節 | 0xxxxxxx(x) | x&0x7f | 0001 - 007F |
雙字節 | 110xxxxx(x) 10xxxxxx(y) | ((x&0x1f)<<6) + (y&0x3f) | 0080 - 07FF |
三字節 | 1110xxxx(x) 10xxxxxx(y) 10xxxxxx(z) | ((x&0xf)<<12) + ((y&0x3f)<<6) + (z&0x3f) | 0800 - FFFF |
六字節 | 11101101(u) 1010xxxx(v) 10xxxxxx(w) 11101101(x) 1011xxxx(y) 10xxxxxx(z) | 0x10000 + ((v&0xf)<<16) + ((w&0x3f)<<10) + ((y&0xf)<<6) + (z&0x3f) | U+FFFF |
參考資料:
http://pcedu.pconline.com.cn/empolder/gj/other/0505/616631_1.html