JAVA字符編碼系列一:Unicode,GBK,GB2312,UTF-8概念基礎

這兩天抽時間又總結/整理了一下各類編碼的實際編碼方式,和在Java應用中的使用狀況,在這裏記錄下來以便往後參考。
爲了構成一個完整的對文字編碼的認識和深刻把握,以便處理在Java開發過程當中遇到的各類問題,特別是亂碼問題,我以爲組成一個系列來描述和分析更好一些,包括三篇文章:
第一篇:JAVA字符編碼系列一:Unicode,GBK,GB2312,UTF-8概念基礎
第二篇:JAVA字符編碼系列二:Unicode,ISO-8859,GBK,UTF-8編碼及相互轉換
第三篇:JAVA字符編碼系列三:Java應用中的編碼問題
 
第一篇:JAVA字符編碼系列一:Unicode,GBK,GB2312,UTF-8概念基礎
本部分採用重用,轉載一篇文章來完成這部分的目標。
來源:holen'blog   對字符編碼與Unicode,ISO 10646,UCS,UTF8,UTF16,GBK,GB2312的理解
地址:http://blog.donews.com/holen/archive/2004/11/30/188182.aspx
 
Unicode:算法

unicode.org制定的編碼機制, 要將全世界經常使用文字都函括進去.
在1.0中是16位編碼, 由U+0000到U+FFFF. 每一個2byte碼對應一個字符; 在2.0開始拋棄了16位限制, 原來的16位做爲基本位平面, 另外增長了16個位平面, 至關於20位編碼, 編碼範圍0到0x10FFFF.編程

UCS:網絡

ISO制定的ISO10646標準所定義的 Universal Character Set, 採用4byte編碼.架構

Unicode與UCS的關係:編程語言

ISO與unicode.org是兩個不一樣的組織, 所以最初制定了不一樣的標準; 但自從unicode2.0開始, unicode採用了與ISO 10646-1相同的字庫和字碼, ISO也承諾ISO10646將不會給超出0x10FFFF的UCS-4編碼賦值, 使得二者保持一致.ide

UCS的編碼方式:函數


UCS-2, 與unicode的2byte編碼基本同樣.工具

UCS-4, 4byte編碼, 目前是在UCS-2前加上2個全零的byte.字體

UTF: Unicode/UCS Transformation Format編碼

UTF-8, 8bit編碼, ASCII不做變換, 其餘字符作變長編碼, 每一個字符1-3 byte. 一般做爲外碼. 有如下優勢:
* 與CPU字節順序無關, 能夠在不一樣平臺之間交流
* 容錯能力高, 任何一個字節損壞後, 最多隻會致使一個編碼碼位損失, 不會鏈鎖錯誤(如GB碼錯一個字節就會整行亂碼)

UTF-16, 16bit編碼, 是變長碼, 大體至關於20位編碼, 值在0到0x10FFFF之間, 基本上就是unicode編碼的實現. 它是變長碼, 與CPU字序有關, 但由於最省空間, 常做爲網絡傳輸的外碼.
UTF-16是unicode的preferred encoding.

UTF-32, 僅使用了unicode範圍(0到0x10FFFF)的32位編碼, 至關於UCS-4的子集.

UTF與unicode的關係:

Unicode是一個字符集, 能夠看做爲內碼.
而UTF是一種編碼方式, 它的出現是由於unicode不適宜在某些場合直接傳輸和處理. UTF-16直接就是unicode編碼, 沒有變換, 但它包含了0x00在編碼內, 頭256字節碼的第一個byte都是0x00, 在操做系統(C語言)中有特殊意義, 會引發問題. 採用UTF-8編碼對unicode的直接編碼做些變換能夠避免這問題, 並帶來一些優勢.

中國國標編碼:

GB 13000: 徹底等同於ISO 10646-1/Unicode 2.1, 從此也將隨ISO 10646/Unicode的標準更改而同步更改.

GBK: 對GB2312的擴充, 以容納GB2312字符集範圍之外的Unicode 2.1的統一漢字部分, 而且增長了部分unicode中沒有的字符.

GB 18030-2000: 基於GB 13000, 做爲Unicode 3.0的GBK擴展版本, 覆蓋了全部unicode編碼, 地位等同於UTF-8, UTF-16, 是一種unicode編碼形式. 變長編碼, 用單字節/雙字節/4字節對字符編碼. GB18030向下兼容GB2312/GBK.
GB 18030是中國全部非手持/嵌入式計算機系統的強制實施標準.

-------------------------------

 

 

什麼是 UCS 和 ISO 10646?
國際標準 ISO 10646 定義了 通用字符集 (Universal Character Set, UCS). UCS 是全部其餘字符集標準的一個超集. 它保證與其餘字符集是雙向兼容的. 就是說, 若是你將任何文本字符串翻譯到 UCS格式, 而後再翻譯回原編碼, 你不會丟失任何信息.

UCS 包含了用於表達全部已知語言的字符. 不只包括拉丁語,希臘語, 斯拉夫語,希伯來語,阿拉伯語,亞美尼亞語和喬治亞語的描述, 還包括中文, 日文和韓文這樣的象形文字, 以及 平假名, 片假名, 孟加拉語, 旁遮普語果魯穆奇字符(Gurmukhi), 泰米爾語, 印.埃納德語(Kannada), Malayalam, 泰國語, 老撾語, 漢語拼音(Bopomofo), Hangul, Devangari, Gujarati, Oriya, Telugu 以及其餘數也數不清的語. 對於尚未加入的語言, 因爲正在研究怎樣在計算機中最好地編碼它們, 於是最終它們都將被加入. 這些語言包括 Tibetian, 高棉語, Runic(古代北歐文字), 埃塞俄比亞語, 其餘象形文字, 以及各類各樣的印-歐語系的語言, 還包括挑選出來的藝術語言好比 Tengwar, Cirth 和 克林貢語(Klingon). UCS 還包括大量的圖形的, 印刷用的, 數學用的和科學用的符號, 包括全部由 TeX, Postscript, MS-DOS,MS-Windows, Macintosh, OCR 字體, 以及許多其餘字處理和出版系統提供的字符.

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裏有些編碼點分配給了 組合字符.它們相似於打字機上的無間隔重音鍵. 單個的組合字符不是一個完整的字符. 它是一個相似於重音符或其餘指示標記, 加在前一個字符後面. 於是, 重音符能夠加在任何字符後面. 那些最重要的被加劇的字符, 就象普通語言的正字法(orthographies of common languages)裏用到的那種, 在 UCS 裏都有本身的位置, 以確保同老的字符集的向後兼容性. 既有本身的編碼位置, 又能夠表示爲一個普通字符跟隨一個組合字符的被加劇字符, 被稱爲 預做字符(precomposed characters). UCS 裏的預做字符是爲了同沒有預做字符的舊編碼, 好比 ISO 8859, 保持向後兼容性而設的. 組合字符機制容許在任何字符後加上重音符或其餘指示標記, 這在科學符號中特別有用, 好比數學方程式和國際音標字母, 可能會須要在一個基本字符後組合上一個或多個指示標記.

組合字符跟隨着被修飾的字符. 好比, 德語中的元音變音字符 ("拉丁大寫字母A 加上分音符"), 既能夠表示爲 UCS 碼 U+00C4 的預做字符, 也能夠表示成一個普通 "拉丁大寫字母A" 跟着一個"組合分音符":U+0041 U+0308 這樣的組合. 當須要堆疊多個重音符, 或在一個基本字符的上面和下面都要加上組合標記時, 可使用多個組合字符. 好比在泰國文中, 一個基本字符最多可加上兩個組合字符.

什麼是 UCS 實現級別?
不是全部的系統都須要支持象組合字符這樣的 UCS 裏全部的先進機制. 所以 ISO 10646 指定了下列三種實現級別:

級別1
不支持組合字符和 Hangul Jamo 字符 (一種特別的, 更加複雜的韓國文的編碼, 使用兩個或三個子字符來編碼一個韓文音節)
級別2
相似於級別1, 但在某些文字中, 容許一列固定的組合字符 (例如, 希伯來文, 阿拉伯文, Devangari, 孟加拉語, 果魯穆奇語, Gujarati, Oriya, 泰米爾語, Telugo, 印.埃納德語, Malayalam, 泰國語和老撾語). 若是沒有這最起碼的幾個組合字符, UCS 就不能完整地表達這些語言.
級別3
支持全部的 UCS 字符, 例如數學家能夠在任意一個字符上加上一個 tilde(顎化符號,西班牙語字母上面的~)或一個箭頭(或二者都加).
什麼是 Unicode?
歷史上, 有兩個獨立的, 創立單一字符集的嘗試. 一個是國際標準化組織(ISO)的 ISO 10646 項目, 另外一個是由(一開始大可能是美國的)多語言軟件製造商組成的協會組織的 Unicode 項目. 幸運的是, 1991年先後, 兩個項目的參與者都認識到, 世界不須要兩個不一樣的單一字符集. 它們合併雙方的工做成果, 併爲創立一個單一編碼表而協同工做. 兩個項目仍都存在並獨立地公佈各自的標準, 但 Unicode 協會和 ISO/IEC JTC1/SC2 都贊成保持 Unicode 和 ISO 10646 標準的碼錶兼容, 並緊密地共同調整任何將來的擴展.

那麼 Unicode 和 ISO 10646 不一樣在什麼地方?
Unicode 協會公佈的 Unicode 標準 嚴密地包含了 ISO 10646-1 實現級別3的基本多語言面. 在兩個標準裏全部的字符都在相同的位置而且有相同的名字.

Unicode 標準額外定義了許多與字符有關的語義符號學, 通常而言是對於實現高質量的印刷出版系統的更好的參考. Unicode 詳細說明了繪製某些語言(好比阿拉伯語)表達形式的算法, 處理雙向文字(好比拉丁與希伯來文混合文字)的算法和 排序與字符串比較 所需的算法, 以及其餘許多東西.

另外一方面, ISO 10646 標準, 就象廣爲人知的 ISO 8859 標準同樣, 只不過是一個簡單的字符集表. 它指定了一些與標準有關的術語, 定義了一些編碼的別名, 幷包括了規範說明, 指定了怎樣使用 UCS 鏈接其餘 ISO 標準的實現, 好比 ISO 6429 和 ISO 2022. 還有一些與 ISO 緊密相關的, 好比 ISO 14651 是關於 UCS 字符串排序的.

考慮到 Unicode 標準有一個易記的名字, 且在任何好的書店裏的 Addison-Wesley 裏有, 只花費 ISO 版本的一小部分, 且包括更多的輔助信息, 於是它成爲使用普遍得多的參考也就不足爲奇了. 然而, 通常認爲, 用於打印 ISO 10646-1 標準的字體在某些方面的質量要高於用於打印 Unicode 2.0的. 專業字體設計者老是被建議說要兩個標準都實現, 但一些提供的樣例字形有顯著的區別. ISO 10646-1 標準一樣使用四種不一樣的風格變體來顯示錶意文字如中文, 日文和韓文 (CJK), 而 Unicode 2.0 的表裏只有中文的變體. 這致使了廣泛的認爲 Unicode 對日本用戶來講是不可接收的傳說, 儘管是錯誤的.

什麼是 UTF-8?
首先 UCS 和 Unicode 只是分配整數給字符的編碼表. 如今存在好幾種將一串字符表示爲一串字節的方法. 最顯而易見的兩種方法是將 Unicode 文本存儲爲 2 個 或 4 個字節序列的串. 這兩種方法的正式名稱分別爲 UCS-2 和 UCS-4. 除非另外指定, 不然大多數的字節都是這樣的(Bigendian convention). 將一個 ASCII 或 Latin-1 的文件轉換成 UCS-2 只需簡單地在每一個 ASCII 字節前插入 0x00. 若是要轉換成 UCS-4, 則必須在每一個 ASCII 字節前插入三個 0x00.

在 Unix 下使用 UCS-2 (或 UCS-4) 會致使很是嚴重的問題. 用這些編碼的字符串會包含一些特殊的字符, 好比 '\0' 或 '/', 它們在 文件名和其餘 C 庫函數參數裏都有特別的含義. 另外, 大多數使用 ASCII 文件的 UNIX 下的工具, 若是不進行重大修改是沒法讀取 16 位的字符的. 基於這些緣由, 在文件名, 文本文件, 環境變量等地方, UCS-2 不適合做爲 Unicode 的外部編碼.

在 ISO 10646-1 Annex R 和 RFC 2279 裏定義的 UTF-8 編碼沒有這些問題. 它是在 Unix 風格的操做系統下使用 Unicode 的明顯的方法.

UTF-8 有一下特性:

UCS 字符 U+0000 到 U+007F (ASCII) 被編碼爲字節 0x00 到 0x7F (ASCII 兼容). 這意味着只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 兩種編碼方式下是同樣的.
全部 >U+007F 的 UCS 字符被編碼爲一個多個字節的串, 每一個字節都有標記位集. 所以, ASCII 字節 (0x00-0x7F) 不可能做爲任何其餘字符的一部分.
表示非 ASCII 字符的多字節串的第一個字節老是在 0xC0 到 0xFD 的範圍裏, 並指出這個字符包含多少個字節. 多字節串的其他字節都在 0x80 到 0xBF 範圍裏. 這使得從新同步很是容易, 並使編碼無國界, 且不多受丟失字節的影響.
能夠編入全部可能的 231個 UCS 代碼
UTF-8 編碼字符理論上能夠最多到 6 個字節長, 然而 16 位 BMP 字符最多隻用到 3 字節長.
Bigendian UCS-4 字節串的排列順序是預約的.
字節 0xFE 和 0xFF 在 UTF-8 編碼中從未用到.
下列字節串用來表示一個字符. 用到哪一個串取決於該字符在 Unicode 中的序號.

U-00000000 - U-0000007F:  0xxxxxxx 
U-00000080 - U-000007FF:  110xxxxx 10xxxxxx 
U-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx 
U-00010000 - U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 
U-00200000 - U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
U-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 

xxx 的位置由字符編碼數的二進制表示的位填入. 越靠右的 x 具備越少的特殊意義. 只用最短的那個足夠表達一個字符編碼數的多字節串. 注意在多字節串中, 第一個字節的開頭"1"的數目就是整個串中字節的數目.

例如: Unicode 字符 U+00A9 = 1010 1001 (版權符號) 在 UTF-8 裏的編碼爲:

11000010 10101001 = 0xC2 0xA9

而字符 U+2260 = 0010 0010 0110 0000 (不等於) 編碼爲:

11100010 10001001 10100000 = 0xE2 0x89 0xA0

這種編碼的官方名字拼寫爲 UTF-8, 其中 UTF 表明 UCS Transformation Format. 請勿在任何文檔中用其餘名字 (好比 utf8 或 UTF_8) 來表示 UTF-8, 固然除非你指的是一個變量名而不是這種編碼自己.

什麼編程語言支持 Unicode?
在大約 1993 年以後開發的大多數現代編程語言都有一個特別的數據類型, 叫作 Unicode/ISO 10646-1 字符. 在 Ada95 中叫 Wide_Character, 在 Java 中叫 char.

ISO C 也詳細說明了處理多字節編碼和寬字符 (wide characters) 的機制, 1994 年 9 月 Amendment 1 to ISO C 發表時又加入了更多. 這些機制主要是爲各種東亞編碼而設計的, 它們比處理 UCS 所需的要健壯得多. UTF-8 是 ISO C 標準調用多字節字符串的編碼的一個例子, wchar_t 類型能夠用來存放 Unicode 字符.

 


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/qinysong/archive/2006/09/05/1179480.aspx

相關文章
相關標籤/搜索