文章目錄
- 在計算機的世界裏,所有的事物都是由 0101 的二進制數字構成
- 如何將現實世界中的事物與 0101 對應起來,這是計算機技術的基石之一
0 字符集與編解碼
- 字符集: 一個字典,收集了很多字符(文化概念,即符號),並給每個符號,確定了一個唯一的代號(code,爲數值)
- 編碼: 將一個字符集中的代號,編碼成 2 進制形式
- 解碼: 將 2 進制形式的 byte 流,解碼成 代號 形式
1 幾種常見的字符集
1.1 ASCII
-
ASCII 既是字符集,也代表編碼方案
-
ASCII 碼,總共有 128 個,用一個字節的低 7 位表示
-
0~31 是控制字符如換行回車刪除等;32~126 是打印字符
1.2 ISO-8859-1
-
ISO-8859-1既是字符集,也代表編解碼方案
-
正式編號爲 ISO/IEC 8859-1:1998,又稱 Latin-1 或 西歐語言
-
它以 ASCII 爲基礎,在空置的0xA0-0xFF的範圍內,加入96個字母 及 符號
-
ISO-8859-1 仍然是單字節編解碼,它總共能表示 256 個字符
-
ISO-8859-1對應於ISO/IEC 10646即 Unicode 的前256個碼位
- 所以 unicode 字符集和 ISO-8859-1 在前 256 個碼位是可以通用的
- 只要超過這個碼位,就會出現亂碼
-
如果文件中只存在 256 碼位之前的,用 ISO-8859-1 將更省帶寬
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<%@ page contentType="text/html;charset= iso-8859-1" %>
1.3 GBK
- GBK 是 GB 2312 的超集,只是字符集
- 它們的編解碼都是基於 EUC-CN 的
- 字符有一字節和雙字節編解碼,
00
–7F
範圍內是第一個字節,和 ASCII 保持一致 - 如果是雙字節字符,第一個字節肯定爲高字節
1.4 Unicode
1.4.1 簡介
- Unicode擴展了code point 的範圍,遠遠超出了ISO-8859-1和字節存儲的8位限制。幾乎所有的口頭和書面語言、數學和其他符號以及歷史語言都指定了Unicode字符
1.4.2 code points
- code points 代表了在 unicode 字符集中,分配給每個字符的數值
1.4.3 Unicode Planes
- 一個 plane 由 65,536 (216) 個 code points 組成
- unicode 共有 17 個 plane
1.4.3.1 BMP
- The first plane, plane 0, the Basic Multilingual Plane (BMP) contains characters for almost all modern languages, and a large number of symbols
1.4.3.2 Supplementary Multilingual Plane (SMP) U+1000 – U+1ffff
- 補增的多語言平面
- 主要用於歷史劇本、音樂和數學符號
1.4.3.3 Higher Planes
- 更高的平面
2 幾種常見的編解碼方式
2.1 ASCII
2.2 ISO-8859-1
2.3 EUC-CN
2.4 UTF-32
- UTF-32 是,Unicode 字符集的一種編解碼方式
- 定長編解碼,每個字符都由 4 個字節來表示,非常簡單,高位補零即可
- 是 USC-4 的子集,編解碼範圍限制在0~0x10FFFF之間
- 優點:編解碼速度快
- 缺點:浪費空間(不考慮壓縮)
2.5 UTF-16
- UTF-16 是,Unicode 字符集的一種編解碼方式
- 變長編解碼,一般情況下都是 2 個字節表示一個字符(code point 在 0-FFFF 之間)
- 如果超過 FFFF 則將使用 2 個 16字節(a surrogate pair of 16 bit,2 個 code unit) 表示 一個字符
- 注: java 中的 char 就是 2 個字節的,即 UTF-16 解碼形式
- 注: java 中對 String 的編解碼操作,最終都會以 UTF-16 的解碼形式存儲到 char 數組中
@Test
public void testUtf() {
//str 內部存儲的是 utf-16 形式的 code unit
String str = "i am 康康";
try {
//將 str 的 code unit 編碼爲 gbk 形式的 bytes,然後在通過 gbk 解碼 bytes
//關鍵是直接解碼成 utf-16 形式的 code unit!這裏並不是解碼成 gbk 對應的 數值碼
//不會亂碼
String str1 = new String(str.getBytes("gbk"),"gbk");
//通過平臺默認編碼(java 爲 utf-8) 將 str 編碼成 utf-8 對應的 bytes
//然後,通過 utf-8 將 byte 直接解碼成 utf-16 的 code unit 形式
//不會亂碼
String str2 = new String(str.getBytes(),"utf-8");
//通過平臺默認編碼(java 爲 utf-8) 將 str 編碼成 utf-8 對應的 bytes
//然後通過 utf-16 解碼 bytes,這裏就會亂碼了,因爲 bytes 對應的編解碼不一樣
String str3 = new String(str.getBytes(),"utf-16");
//通過 ISO-8859-1 編碼 將 str 編碼成對應的 bytes
//然後通過 ISO-8859-1 解碼
//會亂碼,雖然 bytes 對應的編解碼一樣,但是在 str 編碼的時候 用的 ISO-8859-1 它的編解碼範圍是 255,str 中 康對應的 code unit 數值已經大於 255 了,造成了編碼時,把超過範圍的 code 編碼成了 3f,這時對 3f 解碼時,會解碼爲 ?
String str5 = new String(str.getBytes("ISO-8859-1"),"ISO-8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
2.6 USC-2
- USC-2 是,Unicode 字符集的一種編解碼方式
- 定長編解碼,每個字符由 2 個字節表示
- 和 UTF-16 的區別在於,它不支持 surrogate pair
- 在 BMP 上,它們兩可以互換
2.7 UTF-8
-
UTF-8 是,Unicode 字符集的一種編解碼方式
-
是一種存儲效率很高的編碼方式
- ASCII characters 0-127 (decimal) are encoded as a single byte
- Code points U+80 to U+7FF are stored as 2 bytes.
- Code points U+800 to U+FFFF are stored as 3 byte. 中文的 unicode 範圍:4E00-9FA5(常用部分)
- Code points U+10000 U+10FFFF are stored as 4 bytes.
-
unicode <—> utf-8 對照表(很有規律)
字節數 | Unicode | UTF-8編碼 |
---|---|---|
1 | 000000-00007F | 0xxxxxxx |
2 | 000080-0007FF | 110xxxxx 10xxxxxx |
3 | 000800-00FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
4 | 010000-10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
3 Little endian 和 Big endian 與 UTF-8 BOM
- 計算機的發送信息的最小單位是 字節
- 這使得所有以多個字節爲單位的編解碼方案會出現 字節順序的問題,如 UTF-16,UTF-32 等(不包括 UTF-8)
- 第一個字節在前,就是"大頭方式"(Big endian)
- 第二個字節在前就是"小頭方式"(Little endian)
- 在保存爲UTF-8的任何文檔的開頭都添加了字節0xEF,0xBB,0xBF。這是Unicode 字節順序標記(BOM)的UTF-8編解碼,並且即使字節順序與UTF-8無關,也通常稱爲UTF-8 BOM。
- Unicode標準既不要求也不建議使用UTF-8的BOM,但是警告說,從另一種編碼轉碼的文件的開頭可能會遇到BOM
- UTF-8 BOM的存在可能會導致可以處理UTF-8的現有軟件出現問題(不要使用!)
4 在 Windows 記事本的語境中
- 所謂的「ANSI」指的是對應當前系統 locale 的遺留(legacy)編碼
- 所謂的「Unicode」指的是帶有 BOM 的小端序 UTF-16
- 所謂的「UTF-8」指的是帶 BOM 的 UTF-8
參考
A Beginner’s Guide to Understanding Unicode for the Application Programmer and Web Developer
Working with ISO-8859-1 and Unicode Character Sets
細說:Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4
深入分析 Java 中的中文編碼問題