字符集與編碼問題小結

轉自:dbzhang800的 http://hi.baidu.com/cyclone/blog/item/d299af51e04aed868d543064.html

小結得好好呀!

 

字符集與編碼問題小結

2009-07-15 19:57

寫在前面

一直想整理一點文字編碼相關的東西,卻由於能力不夠,始終不知道如何下手。看到論壇中編碼一再被提起,終於決定嘗試着整理一下。

--2010.05.30

編碼的引入

我們都瞭解,計算機只能存儲2進制,也是就010100...,而無法存儲“abc...”。當有人想把文字存儲到計算機時,編碼的故事就開始了...

既然計算機只能,只能存放二進制,那麼我們就把“abc...”通過某種方式變成二進制不就解決了麼?

比如,

  • a 用 01000001 表示,
  • b用 01000010 表示,
  • ... (注:以下爲了書寫簡單,採用0x41 這種形式表示 01000001)

哎,等等,爲什麼要用 0x41 表示 a 呢,如果有人用下面的方式怎麼辦?

  • a 用 0x81 表示,
  • b 用 0x82
  • ...

ASCII

有人用 0x41 代表a,有人用 0x81 表示。語言不通,不同的計算機無法交流。美國人很早發現了這種問題,爲便於交流指定了編碼標準,於是有了:

ASCII (American Standard Code for Information)

  • ASCII碼是7位編碼,但由於計算機基本處理單位爲字節(1byte = 8bit),所以一般仍以一個字節來存放一個ASCII字符。每一個字節中多餘出來的一位(最高位)在計算機內部通常保持爲0。
  • ASCII被定爲國際標準之後的代號爲ISO-646

ISO-8859-*

ASCII 解決了美國人的問題,但很快,其他國家發現了這個編碼不能滿足自己國家的需要。法國、德國等國家暫且不說,英國都發現ASCII有問題:英鎊符號“£”去哪兒了?現在好了,

既想與ASCII兼容,有要添加ASCII沒有的文字符號,怎麼辦?擴展一下吧!

由於ASCII碼只使用了7個二進制位,也就是說一個字節可以表示的256個數字中,它僅使用了0~127這128個碼位,剩下的128個碼位便可以用來做擴展,用來表示一些特定語言所獨有的字符

因此對這多餘的128個碼位的不同擴展,就形成了一系列ISO-8859-*的標準。例如爲英語作了專門擴展的字符集編碼標準編號爲ISO-8859-1,也叫做Latin-1。

ISO-8859-* (*代表1~11,13~16)共15個編碼方案,解決了 拉丁字母的語言(主要是歐洲國家的語言),使用西裏爾字母的東歐語言、希臘語、泰語、現代阿拉伯語、希伯來語等。

* 這些編碼方案在當時解決了這些國家的問題,但不同的編碼如同軍閥割據,同一勢力範圍內交流沒問題,但不能普遍通用。比如 \xA3 在使用 Latin-1 的國家看來,是英鎊符號“£”,而在使用 Latin-2的國家看來,卻是另一個符號 “Ł”。而且無法在一個文件內同時出現這兩個符號。這個問題的解決,需要unicode。

ISO-2022 與 EUC

ISO-8859-* 解決了多數語言的編碼問題,可是,漢語、日語及韓語字數衆多,無法用單一個8位字符來表達,也就是無法通過類似 ISO-8859-*的方式解決。於是有了 ISO-2022

ISO-2022提供了這樣一種技術,它能在一種字符編碼中支持多種字符集,可以用8位或16位來表示一個文字(字符),是一種變長的編碼,這樣,就能表示中日韓的字符了。該編碼還有個顯著的特點,就是所有的字節都是以0開始。

ISO-2022 在日本用的比較普遍,在中國反倒是很少使用。儘管如此,還是用中文的 ISO-2022-CN 簡單說一下:

在繼續之前,我們先提一下GB2312:GB2312 中規定了漢字的區位碼,同時指定 ISO-2022 (等同GB 2311) 爲包裝方式。

漢字“文”字在46區36位,用 ISO 2022 包裝時,字節序列是:

  • <ESC> $ ) A <SO> <0x4E> <0x44> <SI>
  • <ESC> 是字節 0x1b

  • <SO> 是字節 0x0e,表示脫離普通 ASCII 編碼模式,進入特殊編碼模式(這兒指 GB2312 編碼)

  • <SI> 是字節 0x0f,表示返回普通 ASCII 編碼模式

  • 第一字節 0x4E 是在區號 46 的基礎上加上 32,以避開 ASCII 的控制符區(<32)

  • 第二字節 0x44 是在位號 36 的基礎上加上 32,以避開 ASCII 的控制符區(<32)

前面說了,ISO-2022 在國內很少使用,那麼國內用的什麼編碼方案呢?

這就是 EUC-CN:

EUC (Extended Unix Code),是一個主要用於日文、韓文、簡體中文 的多字節編碼系統,它基於ISO-2020標準。它使用了一些兼容於ISO-2022區位碼的94x94編碼表,把每個區位加上0xA0來表示,以便兼容於ASCII。

今天通常說的 GB2312 編碼都是指 EUC 包裝的 GB2312 編碼。

EUC-GB2312 與區位碼的關係:

  • 第1字節 = 區碼 + 32 + 0x80
  • 第2字節 = 位碼 + 32 + 0x80
  • “文”字的 EUC-GB2312 編碼是 0xCE 0xC4

Unicode

Unicode是由於傳統的字符編碼方式的侷限性而產生的,例如:

  • ISO 8859所定義的字符雖然在不同的國家中廣泛地使用,可是在不同國家間卻經常出現不相容的情況。
  • 很多傳統的編碼方式都具有一個共通的問題,即其容許電腦進行雙語環境式的處理(通常是ASCII以及其本地語言),但卻無法同時支援多語言環境式的處理(比如同是處理中文和日文)。

於是一個將所有國家所有語種的所有文字進行統一編碼的方案開始了...

Unicode與UCS

1980年代,有兩個組織分別開始開發適用於各國語言的通用碼,但不久他們便發現了對方的存在。

  • Unicode 組織,由多家計算機軟件公司,還包括一些出版行業的公司共同發起的。採用16位編碼空間
  • ISO-10646 項目組,Universal Character Set(UCS),採用31位編碼空間

ISO與Unicode是兩個不同的組織,因此最初制定了不同的標準;但自從unicode2.0開始,unicode採用了與ISO 10646-1相同的字庫和字碼,ISO也承諾ISO10646將不會給超出0×10FFFF的UCS-4編碼賦值,使得兩者保持一致。最終,兩者統一了抽象字符集(即任何一個在Unicode中存在的字符,在UCS中也存在),且最靠前的65535個字符也統一了字符的編碼。

編碼字符集與字符編碼

在傳統意義上,沒有字符集和編碼的區分,比如GB2312、Latin1等都是既指代字符集又指代編碼方案。

  • 編碼字符集 Coded Character Set
  • 字符編碼 Character Encoding

按照慣例,人們認爲字符集和字符編碼是同義詞,但現代的編碼方案 Unicode,沒有遵循這種慣例。

Unicode 是一個字符集合,它給集合中的每個字符都指定一了個代號。

當我們要把這個代號存到計算機中時,需要把它變成一個字節的序列。不同的變換方式引入了 UTF

  • Unicode 和 UCS 兩者指的都是編碼字符集,而不是字符編碼。
  • UTF: Unicode Transformation Format 是字符編碼

UTF

  • UTF-8, 8bit編碼, ASCII不作變換, 其他字符做變長編碼, 每個字符1-6 byte. 通常作爲外碼. 有以下優點:
    • 與CPU字節順序無關, 可以在不同平臺之間交流
    • 容錯能力高, 任何一個字節損壞後, 最多隻會導致一個編碼碼位損失, 不會鏈鎖錯誤(如GB碼錯一個字節就會整行亂碼)
    • UTF-8用一個字節 表示ASCI字符,用兩個字節表示西歐字符,用三個字符表示亞洲的大部分字符。
  • UTF-16, 16bit編碼, 是變長碼,
    • UTF-16是 unicode的preferred encoding。
    • UCS-2與UTF-16在對前65536個字符的處理上也完全相同,唯一的區別只在於 UCS-2 不支持surrogate pair機制,即是說,UCS-2只能對前65536個字符編碼,對其後的字符毫無辦法。
    • UTF-16是windows平臺上主要使用的編碼方案
  • UTF-32, 僅使用了unicode範圍(0到0×10FFFF)的32位編碼, 相當於UCS-4的子集.
    • Linux下使用的UTF-32方案。

UTF 還涉及到字節序的問題。字節順序標記(Byte Order Mark, 簡稱BOM)出現在Unicode流開端,說明編碼類型。BOM是一個有點小聰明的想法。下面是常用的BOM:

UTF-16 big endian

FE FF

UTF-16 little endian

FF FE

UTF-32 bign endian

00 00 FE FF

UTF-32 little endian

FF FE 00 00

UTF-8 little endian

EF BB BF

GB18030

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

其他

GBK

GBK (Microsoft Code Page 936)

相傳是微軟公司在 EUC-GB2312 的基礎上擴充了 Unicode 1.1 (GB13000.1-93) 而來, 最早出現於 Windows 95。沒有對應的國家標準,只有一個《全國信息技術標準化技術 委員會 漢字內碼擴展規範(GBK) 1.0》。

  • 第1字節 0x80-0xFE
  • 第2字節 0x40-0xFE
  • 這樣一來,GBK (CP936) 就已經打破了 EUC 的規範。

base64

Base64是網絡上最常見的用於傳輸8Bit字節代碼的編碼方式之一

Base64要求把每三個8Bit的字節轉換爲四個6Bit的字節(3*8 = 4*6 = 24),然後把6Bit再添兩位高位0,組成四個8Bit的字節,也就是說,轉換後的字符串理論上將要比原來的長1/3。

HZ

將 EUC-GB2312 的各字節最高位去掉,再在前後分別加上轉義字符,例如“文”:

~{ <0x4E> <0x44> ~}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章