字符編碼簡介 1、字節 字節是計算機中存儲數據的最小單位,一個字節有 8 個位(即二進制位,也叫 bit),能夠表示 0~255 之間的任何一個數(即二進制的 00000000 到 11111111 之間)。你能夠用字節表示任何東西,好比數字、字符、圖像、音樂等,這取決於你如何解釋這個字節。 2、ASCII 字符集 在標準 ASCII 碼中,用一個字節來表示不一樣的字符,字節的最高位(也就是二進制代碼的左邊第一位)被用來作奇偶校驗,因此只剩下 7 個位用來表示不一樣的字符,這樣能表示的字符範圍就變成了 0~127 之間。其中 0~3一、127 這些數值被定義爲控制字符,他們是不能顯示的。32~126 這些數值被定義爲下面的字符: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxy 若是要在計算機中存儲 ASCII 字符串,只須要將這些字符所對應的數值(用來表示字符的數值也叫作碼點)按字節依次存放便可,讀取的時候也只要按字節依次讀出便可。ASCII 字符集沒法表示漢字。 3、Latin1 字符集 若是將標準 ASCII 碼的最高位不用做奇偶校驗,而也用來表示字符的話,那麼就能夠表示 256 個字符,在 ASCII 的基礎上多出了 128 個字符,這個字符集叫作 Latin1 字符集,Latin1 是 ISO-8859-1 的別名,也可寫做 Latin-1。其中 0~127 這些數值的定義與 ASCII 字符集同樣,128~159 這些數值被定義爲控制字符,160~255 這些數值被定義爲下面的字符: ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ 若是要在計算機中存儲 Latin1 字符串,只須要將這些字符所對應的碼點(碼點就是字符所對應的數值)按字節依次存放便可,讀取的時候也只要按字節依次讀出便可。Latin1 字符集沒法表示漢字。 4、ANSI 字符集 因爲 ASCII 字符集或 Latin1 字符集只能表示有限的字符,對於亞洲字符(例如中文、日文、韓文)則沒法表示,因此爲了使計算機支持更多語言,出現了 ANSI 字符集,ANSI 字符集中 0~127 這些數值的定義與 ASCII 字符集同樣,而 128~255 這些數值被定義爲雙字節字符的一個編碼,即「用其中的 2 個數值來表示 1 個字符」,這樣的雙字節能夠表示的字符數量就達到了 1.6 萬多個。 具體哪 2 個數值表明哪 1 個字符,則由各個國家本身去定義,不一樣國家的 ANSI 字符集是不一樣的,在中文系統下,ANSI 表明 GB2312 字符集,在日文系統下,ANSI 表明 JIS 字符集,不一樣 ANSI 編碼之間互不兼容,當信息在國際間交流時,沒法將屬於兩種語言的文字,存儲在同一段 ANSI 編碼的文本中。 因爲 ANSI 字符串中的字符,有單字節和雙字節之分,因此在存取的時候要判斷當前字節是 0~127 範圍的單字節,仍是 128~255 範圍的雙字節,並作相應處理,才能獲得正確的字符,這樣的判斷和處理就稱爲編碼和解碼。編碼是將字符(碼點)轉換爲字節(單字節或雙字節)保存起來,解碼是將字節(單字節或雙字節)還原爲字符(碼點)顯示出來。 ANSI 字符集存在的 BUG:當你在一個空文本文檔中輸入「聯通」兩個字,並保存爲 ANSI 格式,再次打開的時候,內容將顯示爲亂碼,這是由於,當文本文檔中的全部的字符都知足「192 ≤ 第一字節 ≤ 223 且 128 ≤ 第二字節 ≤ 191」的時候,Windows 就沒法正確識別文檔的編碼格式,錯誤的將 ANSI 格式識別成了 UTF-8 格式,形成解碼錯誤,造成亂碼。 因此在保存文本文檔的時候,不推薦使用 ANSI 編碼格式保存,而應該使用更好的 UTF-8 或 Unicode 編碼格式。 5、UCS 和 Unicode 字符集 因爲 ANSI 字符集的範圍有限,不能包含世界上的全部字符,沒法用於多語言環境(指可同時處理多種語言混合的狀況),因此出現了 UCS 和 Unicode 字符集,UCS(Universal Character Set,通用字符集)使用 4 個字節來表示一個字符,其中最高字節的最高二進制位始終爲 0,這樣可以表示的字符數量就達到了約 20 億個,足以容納全世界全部的字符。在 UCS 字符集中,0~255 這些數值的定義與 Latin1 同樣,只不過是用 4 個字節表示 1 個字符,除最低位字節外,其它 3 個字節所有用 0 填充。這樣就保證了與 Latin1 字符集的兼容。 UCS 是由 ISO 制定的 ISO 10646(或稱 ISO/IEC 10646)標準所定義的標準字符集。UCS 將最高字節定義爲 2^7=128 個組(group),每一個組再根據次高字節分爲 256 個平面(plane),每一個平面再根據次低字節分爲 256 行(row),每行再根據最低字節分爲 256 個碼位(cell)。UCS 中第 0 組的第 0 平面被稱爲「基本多文種平面」,裏面存放了包含世界各國的經常使用字符。除了第 0 平面,UCS 還定義了 16 個輔助平面,用來存放更多的字符。 Unicode 字符集是 UCS 字符集的子集,只包含 0x0~0x10FFFF 範圍的字符。Unicode 3.0 及其如下版本只包含了「基本多文種平面」中的字符(即:0x0~0xFFFF),能夠只使用 2 個字節來表示一個字符。Unicode 3.1 及其以上版本包含了 UCS 中的 16 個輔助平面(即:0x0~0x10FFF)。須要用 4 個字節來表示一個「基本多文種平面」之外的字符。 「基本多文種平面」中有一個專用區「0xE000~0xF8FF」,有 6400 個碼位,用來存放用戶自定義的字符。還有一個被稱做代理區(Surrogate)的特殊區域「0xD800~0xDFFF」,共 2048 個碼位,代理區的目的是用兩個 UTF-16 編碼表示「基本多文種平面」之外的字符。具體參照「UTF16 編碼」的介紹。 歷史上存在着兩個獨立的嘗試創立單一字符集的組織,即國際標準化組織(ISO)和多語言軟件製造商組成的統一碼聯盟。前者開發 ISO/IEC 10646(UCS)項目,後者開發 Unicode 項目。所以最初制定了不一樣的標準。1991 年先後,兩個項目的參與者都認識到,世界不須要兩個不兼容的字符集。因而,它們開始合併雙方的工做成果,併爲創立一個單一編碼表而協同工做。從 Unicode 2.0 開始,Unicode 採用了與 ISO 10646-1 相同的字庫和字碼;ISO 也承諾,ISO 10646 將不會給超出 U+10FFFF 的 UCS-4 編碼賦值,以使得二者保持一致。兩個項目仍都存在,並獨立地公佈各自的標準。因爲 Unicode 這一名字比較好記,於是它使用更爲普遍。 6、Unicode 編碼方式 前面講的 Unicode 字符集中的字符,只是單個的字符形式,若是要將多個 Unicode 字符保存到文件中,則須要一個編碼方式,將 Unicode 碼點轉換爲字節存放到文件中,目前經常使用的編碼方式有:UTF-3二、UTF-1六、UTF-8 等。 UTF 是「Unicode/UCS Transformation Format」的首字母縮寫,即「把 Unicode 字符轉換爲某種格式」之意。 UTF-32 對每個 Unicode 碼點使用 4 個字節表示。UTF-32 足以表示 Unicode 全部組全部平面中的全部字符,可是咱們一般用不到那麼多平面,咱們經常使用的只有「基本多文種平面」,對於這個平面中的字符而言,只用 2 個字節來表示就足夠了,對於歐洲國家而言,一般只使用 ASCII 字符,若是使用 UTF-32 來保存,將浪費很大的存儲空間。因此,UTF-32 在實際中用的並很少。 UTF-16 對每個 Unicode 碼點使用 2 個或 4 個字節表示,「基本多文種平面」內的字符使用 2 個字節足以所有表示出來,而「基本多文種平面」外的字符,則須要用到「代理區域(0xD800~0xDFFF)」,「代理區域」中的數值永久保留,不與 Unicode 字符進行映射。UTF-16 就利用保留下來的 0xD800~0xDFFF 中的數值來對「基本多文種平面」之外的字符進行編碼。UTF-16 的編碼規則以下: 若是 Unicode 字符的碼點在 0x0~0xFFFF 範圍內,則直接用 Unicode 碼點的最低 2 個字節做爲其 UTF-16 的編碼值。 若是 Unicode 字符的碼點在 0x01FFFF~0x10FFFF 範圍內,則將該碼點的數值減去 0x10000,而後將結果的二進制值(共 20 位)從中間分開成兩部分(高 10 位和低 10 位),高 10 位的值(值的範圍爲 0x0~0x3FF)被加上 0xD800 獲得第一個碼元(或稱做前導代理,值的範圍是 0xD800~0xDBFF,佔用 2 個字節)。低 10 位值(值的範圍也是 0x0~0x3FF)被加上 0xDC00 獲得第二個碼元(或稱做後尾代理,值的範圍是 0xDC00~0xDFFF,佔用 2 個字節)。這兩個碼元合在一塊兒就構成了一個 4 字節的 UTF-16 編碼,這樣 UTF-16 就能夠表示整個 Unicode 範圍內的全部字符了。因而可知,UTF-16 是一種變長的編碼方式,它的編碼長度不固定,有些字符用 2 個字節表示,有些字符用 4 個字節表示。UTF-16 的編碼方式也叫 Unicode 編碼方式。 UTF-8 對每個 Unicode 碼點使用 一、二、三、4 個字節表示,也是一種變長的編碼方式。 對於 0x0~0x7F 之間的字符,使用 1 個字節表示,與 ASCII 字符集徹底相同。 對於 0x80~0x7FF 之間的字符,使用 2 個字節表示,表示方法爲,將該 Unicode 字符的二進制編碼按順序填入「110xxxxx 10xxxxxx」的 x 中便可獲得 2 個字節的 UTF-8 編碼。其中 110 是 UTF-8 編碼的第一個字節標記,有了此標記,就說明該字節是一個 UTF-8 字符編碼的開頭字節,並且 110 中的 2 個 1 表示該 UTF-8 字符編碼是由 2 個字節組成,後面 10 開頭的字節表示 UTF-8 的後續字節。將這 2 個字節讀出來,而後解碼,就能夠獲得一個 Unicode 字符。 對於 0x800~0xFFFF 之間的字符,使用 3 個字節表示,表示方法爲,將該 Unicode 字符的二進制編碼按順序填入「1110xxxx 10xxxxxx 10xxxxxx」的 x 中便可獲得 3 個字節的 UTF-8 編碼。其中 1110 是 UTF-8 編碼的第一個字節標記,有了此標記,就說明該字節是一個 UTF-8 字符編碼的開頭字節,並且 1110 中的 3 個 1 表示該 UTF-8 字符編碼是由 3 個字節組成,後面 10 開頭的字節表示 UTF-8 的後續字節。將這 3 個字節讀出來,而後解碼,就能夠獲得一個 Unicode 字符。 對於 0x10000~0x10FFFF 之間的字符,使用 4 個字節表示,表示方法爲,將該 Unicode 字符的二進制編碼按順序填入「11110xxx 10xxxxxx 10xxxxxx 10xxxxxx」的 x 中便可獲得 4 個字節的 UTF-8 編碼。其中 11110 是 UTF-8 編碼的第一個字節標記,有了此標記,就說明該字節是一個 UTF-8 字符編碼的開頭字節,並且 11110 中的 4 個 1 表示該 UTF-8 字符編碼是由 4 個字節組成,後面 10 開頭的字節表示 UTF-8 的後續字節。將這 4 個字節讀出來,而後解碼,就能夠獲得一個 Unicode 字符。 7、BOM 在 UTF-32 和 UTF-16 編碼中,有些系統將編碼的高位字節放前面,低位字節放後面,而有些系統則恰好相反,這就形成不一樣系統之間,由於存放字節的順序不一樣,而互相不兼容的狀況。爲了解決這個問題,UCS 建議在整個 UTF-32 或 UTF-16 編碼流的起始位置添加一個標記,用來標識該編碼流的字節存放順序。 在 UCS 編碼中有一個叫作「Zero Width No-Break Space」(中文譯做「零寬無間斷間隔」)的字符,它的編碼是 FEFF。而另外一個編碼 FFFE 在 UCS 中是不存在的字符,因此不該該出如今實際傳輸中。UCS 規範建議咱們在傳輸字節流前,先傳輸 BOM(Byte Order Mark,字節順序標號)標記。這樣若是接收者收到 FEFF,就代表這個字節流是 Big-Endian 格式(高位字節在後);若是收到 FFFE,就代表這個字節流是 Little- Endian 格式(低位字節在後)。所以像 FEFF、FFFE 這樣的標記又被稱做 BOM。 在 Windows 和 Unix 系統中,UTF-32 和 UTF-16 使用的是 Little-Endian 字節順序,而在 Mac 系統中則使用 Big-Endian 字節順序。 UTF-8 編碼的字節順序是固定的,在編碼的時候就定好了。若是在 UTF-8 編碼中使用 BOM(UTF-8 的 BOM 爲 EFBBBF),則 BOM 只能用來標示它是一個 UTF-8 文件,而不用來講明字節順序。 8、總結 字符集的概念比較簡單,就是將數值與字符一一對映起來便可,該數值就是該字符的碼點,好比 ASCII 字符集、Latin1 字符集、Unicode 字符集,一個數值對應一個字符。 要將字符集中的多個字符保存到文件中,就不那麼容易了,對於 ASCII、Latin1 這樣的單字節字符集而言,保存到文件是比較簡單的,將碼點按順序寫入文件便可。而對於 Unicode 這樣的多字節字符集而言,要保存到文件,就要考慮效率和空間利用率問題,既要高效率,又不能浪費太多空間,因此就出現了各類各樣的 UTF 編碼方式。 對於歐洲國家而言,使用 UTF-8 編碼保存文本比較合適,對於亞洲國家而言,使用 UTF-16 編碼(即 Unicode 編碼)保存文本比較合適。 對於比較特殊的 ANSI 字符集,因爲它的字符集在不一樣的國家是不同的,各國之間互不兼容,並且容量比較小,仍是棄之不用比較好。