XML學習筆記(一):關於字元編碼的理解

weixin_34120274發表於2019-01-12

歷史上, 有兩個獨立的,創立單一字符集的嘗試。一個是國際標準化組織(ISO)的 ISO 10646 專案,另一個是由(一開始大多是美國的)多語言軟體製造商組成的協會組織的 Unicode 專案。幸運的是, 1991年前後,兩個專案的參與者都認識到,世界不需要兩個不同的單一字符集。它們合併雙方的工作成果, 併為創立一個單一編碼表而協同工作。兩個專案仍都存在並獨立地公佈各自的標準, 但 Unicode 協會和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 標準的碼錶相容,並緊密地共同調整任何未來的擴充套件。Unicode最初設計是作為一種固定寬度的16位字元編碼。但是現在看來,16位編碼的所有65536個字元並不能完全表示全世界所有正在使用或曾經使用的字元。於是,Unicode標準已經擴充套件到包含1112064個字元。那些超出原來的16位限制的字元被稱作增補字元。Unicode標準2.0版是第一個包含啟用增補字元設計的版本。但是,直到 3.1 版才收入第一批增補字符集。中國政府要求支援 GB18030(一種對整個 Unicode 字符集進行編碼的字元編碼標準),因此,如果是 Unicode 3.1 版或更新版本,則將包括增補字元。不幸的是,引入增補字元使字元模型變得更加複雜了。在過去,我們可以簡單地說“字元”,在一個基於 Unicode 的環境(例如 Java 平臺)中,假定字元有 16 位,而現在我們需要更多的術語。

字元是抽象的最小文字單位。它沒有固定的形狀(可能是一個字形),而且沒有值。。“A”是一個字元,“€”(德國、法國和許多其他歐洲國家通用貨幣的標誌)也是一個字元。

字符集是字元的集合。例如,漢字字元是中國人最先發明的字元。

編碼字符集是一個字符集,它為每一個字元分配一個唯一數字。Unicode 標準的核心是一個編碼字符集,字母“A”的編碼為 0041和字元“€”的編碼為 20AC。Unicode 標準始終使用十六進位制數字,而且在書寫時在前面加上字首“U+”,所以“A”的編碼書寫為“U+0041”。

程式碼點是指可用於編碼字符集的數字。編碼字符集定義一個有效的程式碼點範圍,但是並不一定將字元分配給所有這些程式碼點。有效的 Unicode 程式碼點範圍是 U+0000 至 U+10FFFF。Unicode 4.0 將字元分配給一百多萬個程式碼點中的 96,382 程式碼點。

增補字元是程式碼點在 U+10000 至 U+10FFFF 範圍之間的字元,也就是那些使用原始的 Unicode 的 16 位設計無法表示的字元。從 U+0000 至 U+FFFF 之間的字符集有時候被稱為基本多語言面 (BMP)。因此,每一個 Unicode 字元要麼屬於 BMP,要麼屬於增補字元。

字元編碼方案是從一個或多個編碼字符集到一個或多個固定寬度程式碼單元序列的對映。最常用的程式碼單元是位元組,但是 16 位或 32 位整數也可用於內部處理。UTF-32、UTF-16 和 UTF-8 是 Unicode 標準的編碼字符集的字元編碼方案。

通用字符集 (Universal Character Set, UCS)由國際標準 ISO 10646 定義。 UCS 是所有其他字符集標準的一個超集。與其他字符集是雙向相容的。就是說, 如果你將任何文字字串翻譯到 UCS格式,然後再翻譯回原編碼,你不會丟失任何資訊。

UCS 包含了用於表達所有已知語言的字元。ISO 10646 定義了一個 31 位的字符集。 然而,在這巨大的編碼空間中, 迄今為止只分配了前 65534 個碼位 (0x0000 到 0xFFFD)。這個 UCS 的 16位子集稱為 基本多語言面 (Basic Multilingual Plane, BMP)。將被編碼在 16 位 BMP 以外的字元都屬於非常特殊的字元(比如象形文字),且只有專家在歷史和科學領域裡才會用到它們。按當前的計劃, 將來也許再也不會有字元被分配到從 0x000000 到 0x10FFFF 這個覆蓋了超過 100 萬個潛在的未來字元的 21 位的編碼空間以外去了。ISO 10646-1 標準第一次發表於 1993 年,定義了字符集與 BMP 中內容的架構。定義 BMP 以外的字元編碼的第二部分 ISO 10646-2 正在準備中,但也許要過好幾年才能完成。新的字元仍源源不斷地加入到 BMP 中,但已經存在的字元是穩定的且不會再改變了。

UCS 不僅給每個字元分配一個程式碼,而且賦予了一個正式的名字。表示一個 UCS 或 Unicode 值的十六進位制數,通常在前面加上 "U+",就象 U+0041 代表字元"拉丁大寫字母A"。UCS 字元 U+0000 到 U+007F 與 US-ASCII(ISO 646) 是一致的, U+0000 到 U+00FF 與 ISO 8859-1(Latin-1) 也是一致的。從 U+E000 到U+F8FF,已經 BMP 以外的大範圍的編碼是為私用保留的。

UCS裡有些編碼點分配給了組合字元。它們類似於打字機上的無間隔重音鍵。 單個的組合字元不是一個完整的字元。它是一個類似於重音符或其他指示標記,加在前一個字元後面。因而, 重音符可以加在任何字元後面。那些最重要的被加重的字元 在 UCS 裡都有自己的位置,以確保同老的字符集的向後相容性。既有自己的編碼位置,又可以表示為一個普通字元跟隨一個組合字元的被加重字元,被稱為預作字元(precomposed characters)。UCS 裡的預作字元是為了同沒有預作字元的舊編碼,比如 ISO 8859,保持向後相容性而設的。組合字元機制允許在任何字元後加上重音符或其他指示標記,這在科學符號中特別有用,比如數學方程式和國際音標字母,可能會需要在一個基本字元後組合上一個或多個指示標記。組合字元跟隨著被修飾的字元。比如, 德語中的母音變音字元 ("拉丁大寫字母A 加上分音符"),既可以表示為 UCS 碼 U+00C4 的預作字元,也可以表示成一個普通 "拉丁大寫字母A" 跟著一個"組合分音符":U+0041 U+0308 這樣的組合。當需要堆疊多個重音符,或在一個基本字元的上面和下面都要加上組合標記時,可以使用多個組合字元。比如在泰國文中,一個基本字元最多可加上兩個組合字元。

UTF-32 即將每一個 Unicode 程式碼點表示為相同值的 32 位整數。很明顯,它是內部處理最方便的表達方式,但是,如果作為一般字串表達方式,則要消耗更多的記憶體。

UTF-16 使用一個或兩個未分配的 16 位程式碼單元的序列對 Unicode 程式碼點進行編碼。值 U+0000 至 U+FFFF 編碼為一個相同值的 16 位單元。增補字元編碼為兩個程式碼單元,第一個單元來自於高代理範圍(U+D800 至 U+DBFF),第二個單元來自於低代理範圍(U+DC00 至 U+DFFF)。這在概念上可能看起來類似於多位元組編碼,但是其中有一個重要區別:值 U+D800 至 U+DFFF 保留用於 UTF-16;沒有這些值分配字元作為程式碼點。這意味著,對於一個字串中的每個單獨的程式碼單元,軟體可以識別是否該程式碼單元表示某個單單元字元,或者是否該程式碼單元是某個雙單元字元的第一個或第二單元。這相當於某些傳統的多位元組字元編碼來說是一個顯著的改進,在傳統的多位元組字元編碼中,位元組值 0x41 既可能表示字母“A”,也可能是一個雙位元組字元的第二個位元組。

UTF-8 使用一至四個位元組的序列對編碼 Unicode 程式碼點進行編碼。U+0000 至 U+007F 使用一個位元組編碼,U+0080 至 U+07FF 使用兩個位元組,U+0800 至 U+FFFF 使用三個位元組,而 U+10000 至 U+10FFFF 使用四個位元組。UTF-8 設計原理為:位元組值 0x00 至 0x7F 始終表示程式碼點 U+0000 至 U+007F(Basic Latin 字元子集,它對應 ASCII 字符集)。這些位元組值永遠不會表示其他程式碼點,這一特性使 UTF-8 可以很方便地在軟體中將特殊的含義賦予某些 ASCII 字元。

Unicode 提供了一種標準的方法來編碼多語言,而我們常用的GB編碼僅包含了漢字和ascii字元。基本上,假如從顯示的角度理解,假如使用者軟體僅支援GB,假如輸入漢字“啊”,就是將“啊”從內碼(0xB0A1)轉換為Unicode(0x554A),通過0x554A查詢碼錶得到點陣字型檔中的“啊”字儲存位置,獲得點陣陣列,顯示。

4E00--9FFF:CJK Unified Ideographs 這是漢字在碼錶中的位置。

 

相關文章