unicode,mbcs,utf-8,utf-16,utf-32,big endian,little endian
ASCII(American Standard Code for Information Interchange)
? 美國信息交換標準代碼,這是計算機上最早使用的通用的編碼方案。那個時候計算機還只是拉丁文字的專利,根本沒有想到現在計算機的發展勢頭,如果想到了,可能一開始就會使用 unicode 了。當時絕大部分專家都認為,要用計算機,必須熟練掌握英文。這種編碼占用 7 個 Bit ,在計算機中占用一個字節, 8 位,最高位沒用,通訊的時候有時用作奇偶校驗位。因此 ASCII 編碼的取值范圍實際上是: 0x00-0x7f, 只能表示 128 個字符。后來發現 128 個不太夠用,做了擴展,叫做 ASCII 擴展編碼,用足八位,取值范圍變成: 0x00-0xff, 能表示 256 個字符。其實這種擴展意義不大,因為 256 個字符表示一些非拉丁文字遠遠不夠,但是表示拉丁文字,又用不完。所以擴展的意義還是為了下面的 ANSI 編碼服務。
ANSI ( American National Standard Institite )
美國國家標準協會,也就是說,每個國家(非拉丁語系國家)自己制定自己的文字的編碼規則,并得到了 ANSI 認可,符合 ANSI 的標準,全世界在表示對應國家文字的時候都通用這種編碼就叫 ANSI 編碼。換句話說,中國的 ANSI 編碼和在日本的 ANSI 的意思是不一樣的,因為都代表自己國家的文字編碼標準。比如中國的 ANSI 對應就是 GB2312 標準,日本就是 JIT 標準,香港,臺灣對應的是 BIG5 標準等等。當然這個問題也比較復雜,微軟從 95 開始,用就是自己搞的一個標準 GBK 。 GB2312 里面只有 6763 個漢字, 682 個符號,所以確實有時候不是很夠用。 GBK 一直能和 GB2312 相互混淆并且相安無事的一個重要原因是 GBK 全面兼容 GB2312 ,所以沒有出現任何沖突,你用 GB2312 編碼的文件通過 GBK 去解釋一定能獲得相同的顯示效果,換句話說: GBK 對 GB2312 就是,你有的,我也有,你沒得的,我還有!
?
好了, ANSI 的標準是什么呢,首先是 ASCII 的代碼你不能用!也就是說 ASCII 碼在任何 ANSI 中應該都是相同的。其他的,你們自己擴展。所以呢,中國人就把 ASCII 碼變成 8 位, 0x7f 之前我不動你的,我從 0xa0 開始編, 0xa0 到 0xff 才 95 個碼位,對于中國字那簡直是杯水車薪,因此,就用兩個字節吧,因此編碼范圍就從 0xA1A1 - 0xFEFE ,這個范圍可以表示
23901 個漢字。基本夠用了吧, GB2312 才 7000 多個呢! GBK 更猛,編碼范圍是從 0x8140 - 0xFEFE, 可以表示 3 萬多個漢字。可以看出,這兩種方案,都能保證漢字頭一個字節在 0x7f 以上,從而和 ASCII 不會發生沖突。能夠實現英文和漢字同時顯示。 BIG5 ,香港和臺灣用的比較多,繁體,范圍: 0xA140 - 0xF9FE, 0xA1A1 - 0xF9FE ,每個字由兩個字節組成,其第一
字節編碼范圍為 0xA1~0xF9 ,第二字節編碼范圍為 0x40-0x7E 與 0xA1-0xFE ,總計收入 13868 個字 ( 包括 5401 個常用字、 7652 個次常用字、 7 個擴充字、以及 808 個各式符號 ) 。
?
那么到底 ANSI 是多少位呢?這個不一定!比如在 GB2312 和 GBK , BIG5 中,是兩位!但是其他標準或者其他語言如果不夠用,就完全可能不止兩位!
例如:
GB18030:
GB18030-2000(GBK2K)
在
GBK
的基礎上進一步擴展了漢字,增加了藏、蒙等少數民族的字形。
GBK2K
從根本上解決了字位不夠,字形不足的問題。它有幾個特點:它并沒有確定所有的字形,只是規定了編碼范圍,留待以后擴充。編碼是變長的,其二字節部分與
GBK
兼容;四字節部分是擴充的字形、字位,其編碼范圍是首字節
0x81-0xfe
、二字節
0x30-0x39 、三字節 0x81-0xfe 、四字節 0x30-0x39 。它的推廣是分階段的,首先要求實現的是能夠完全映射到 Unicode3.0 標準的所有字形。它是國家標準,是強制性的。
搞懂了 ANSI 的含義,我們發現 ANSI 有個致命的缺陷,就是每個標準是各自為陣的,不保證能兼容。換句話說,要同時顯示中文和日本文或者阿拉伯文,就完全可能會出現一個編碼兩個字符集里面都有對應,不知道該顯示哪一個的問題,也就是編碼重疊的問題。顯然這樣的方案不好,所以 Unicode 才會出現!
3.MBCS ( Multi-Byte Chactacter System ( Set) )
? 多字節字符系統或者字符集,基于 ANSI 編碼的原理上,對一個字符的表示實際上無法確定他需要占用幾個字節的,只能從編碼本身來區分和解釋。因此計算機在存儲的時候,就是采用多字節存儲的形式。也就是你需要幾個字節我給你放幾個字節,比如 A 我給你放一個字節,比如 " 中 “ ,我就給你放兩個字節,這樣的字符表示形式就是 MBCS 。
在基于 GBK 的 windows 中,不會超過 2 個字節,所以 windows 這種表示形式有叫做 DBCS ( Double-Byte Chactacter System ),其實算是 MBCS 的一個特例。
C
語言默認存放字符串就是用的
MBCS
格式。從原理上來說,這樣是非常經濟的一種方式。
4.CodePage
代碼頁,最早來自 IBM ,后來被微軟, oracle ,SAP 等廣泛采用。因為 ANSI 編碼每個國家都不統一,不兼容,可能導致沖突,所以一個系統在處理文字的時候,必須要告訴計算機你的 ANSI 是哪個國家和地區的標準,這種國家和標準的代號(其實就是字符編碼格式的代號),微軟稱為 Codepage 代碼頁,其實這個代碼頁和字符集編碼的意思是一樣的。告訴你代碼頁,本質就是告訴了你編碼格式。但是不同廠家的代碼頁可能是完全不同,哪怕是同樣的編碼,比如, UTF-8 字符編碼 在 IBM 對應的代碼頁是 1208 ,在微軟對應的是 65001, 在德國的 SAP 公司對應的是 4110 。所以啊,其實本來就是一個東西,大家各自為政,搞那么多新名詞,實在沒必要!所以標準還是很重要的!!!
比如 GBK 的在微軟的代碼頁是 936 ,告訴你代碼頁是 936 其實和告訴你我編碼格式是 GBK 效果完全相同。那么處理文本的時候就不會有問題,不會去考慮某個代碼是顯示的韓文還是中文,同樣,日文和韓文的代碼頁就和中文不同,這樣就可以
避免編碼沖突導致計算機不知如何處理的問題。當然用這個也可以很容易的切換語言版本。
但是這都是治標不治本的方法,還是無法解決同時顯示多種語言的問題,所以最后還是都用
unicode
吧,永遠不會有沖突了。
5.Unicode(Universal Code)
?
這是一個編碼方案,說白了就是一張包含全世界所有文字的一個編碼表,不管你用的上,用不上,不管是現在用的,還是以前用過的,只要這個世界上存在的文字符號,統統給你一個唯一的編碼,這樣就不可能有任何沖突了。不管你要同時顯示任何文字,都沒有問題。
?
因此在這樣的方案下,
Unicode
出現了。
Unicode
編碼范圍是:
0-0x10FFFF
,可以容納
1114112
個字符,
100
多萬啊。全世界的字符根本用不完了,
Unicode 5.0
版本中,才用了
238605
個碼位。所以足夠了。
因此從碼位范圍看,嚴格的 unicode 需要 3 個字節來存儲。但是考慮到理解性和計算機處理的方便性,理論上還是用 4 個字節來描述。
Unicode 采用的漢字相關編碼用的是《 CJK 統一漢字編碼字符集》 — 國家標準 GB13000.1 是完全等同于國際標準《通用多八位編碼字符集 (UCS) 》 ISO 10646.1 。《 GB13000.1 》中最重要的也經常被采用的是其雙字節形式的基本多文種平面。在這 65536 個碼位的空間中,定義了幾乎所有國家或地區的語言文字和符號。其中從 0x4E00 到 0x9FA5 的連續區域包含了 20902 個來自中國(包括臺灣)、日本、韓國的漢字,稱為 CJK (Chinese Japanese Korean) 漢字。 CJK 是《 GB2312-80 》、《 BIG5 》等字符集的超集。 CJK 包含了中國,日本,韓國,越南,香港,也就是 CJKVH 。這個在 UNICODE 的 Charset chart 中可以明顯看到。 unicode 的相關標準可以從 unicode.org 上面獲得,目前已經進行到了 6.0 版本。
下面這段描述來自百度百科:
Unicode
字符集可以簡寫為
UCS
(
Unicode Character Set
)。早期的
? unicodeUnicode
標準有
UCS-2
、
UCS-4
的說法。
UCS-2
用兩個字節編碼,
UCS-4
用
4
個字節編碼。
UCS-4
根據最高位為
0
的最高字節分成
2^7=128
個
group
。每個
group
再根據次高字節分為
256
個平面(
plane
)。每個平面根據第
3
個字節分為
256
行
(
row
),每行有
256
個碼位(
cell
)。
group 0
的平面
0
被稱作
BMP
(
Basic Multilingual Plane
)。將
UCS-4
的
BMP
去掉前面的兩個零字節就得到了
UCS-2
。每個平面有
2^16=65536
個碼位。
Unicode
計劃使用了
17
個平面,一共有
17*65536=1114112
個碼位。在
Unicode 5.0.0
版本中,已定義的碼位只有
238605
個,分布在平面
0
、平面
1
、平面
2
、平面
14
、平面
15
、平面
16
。其中平面
15
和平面
16
上只是定義了兩個各占
65534
個碼位的專用區(
Private Use Area
),分別是
0xF0000-0xFFFFD
和
0x100000-0x10FFFD
。所謂專用區,就是保留給大家放自定義字符的區域,可以簡寫為
PUA
。
平面
0
也有一個專用區:
0xE000-0xF8FF
,有
6400
個碼位。平面
0
的
0xD800-0xDFFF
,共
2048
個碼位,是一個被稱作代理區(
Surrogate
)的特殊區域。代理區的目的用兩個
UTF-16
字符表示
BMP
以外的字符。在介紹
UTF-16
編碼時會介紹。如前所述在
Unicode 5.0.0
版本中,
238605-65534*2-6400-2408=99089
。余下的
99089
個已定義碼位分布在平面
0
、平面
1
、平面
2
和平面
14
上,它們對應著
Unicode
目前定義的
99089
個字符,其中包括
71226
個漢字。平面
0
、平面
1
、平面
2
和平面
14
上分別定義了
52080
、
3419
、
43253
和
337
個字符。平面
2
的
43253
個字符都是漢字。平面
0
上定義了
27973
個漢字。
?
6.Unicode 的實現方案
Unicode 其實只是一張巨大的編碼表。要在計算機里面實現,也出現了幾種不同的方案。也就是說如何表示 unicode 編碼的問題。
UTF-8 ( UCS Transformation Format 8bit)
這個方案的意思以 8 位為單位來標識文字,注意并不是說一個文字用 8 位標識。他其實是一種 MBCS 方案,可變字節的。到底需要幾個字節表示一個符號,這個要根據這個符號的 unicode 編碼來決定,最多 4 個字節。
編碼規則如下:
Unicode
編碼
(16
進制
)
║
UTF-8
字節流
(
二進制
)
000000 - 00007F
║
0xxxxxxx
000080 - 0007FF
║
110xxxxx 10xxxxxx
000800 - 00FFFF
║
1110xxxx 10xxxxxx
10xxxxxx
010000 - 10FFFF
║
11110xxx 10xxxxxx
10xxxxxx 10xxxxxx
UTF-8
的特點是對不同范圍的字符使用不同長度的編碼。對于
0x00-0x7F
之間的字符,
UTF-8
編碼與
ASCII
編碼完全相同。
UTF-8 編碼的最大長度是 4 個字節。從上表可以看出, 4 字節模板有 21 個 x ,即可以容納 21 位二進制數字。 Unicode 的最大碼位 0x10FFFF 也只有 21 位。
例
1
:
“
漢
”
字的
Unicode
編碼是
0x6C49
。
0x6C49
在
0x0800-0xFFFF
之間,使用用
3
字節模板了:
1110xxxx
10xxxxxx 10xxxxxx
。將
0x6C49
寫成二進制是:
0110 1100 0100 1001
,
用這個比特流依次代替模板中的
x
,得到:
11100110 10110001 10001001
,即
E6 B1 89
。
例
2
:
Unicode
編碼
0x20C30
在
0x010000-0x10FFFF
之間,使用用
4
字節模板了:
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
。
將 0x20C30 寫成 21 位二進制數字(不足 21 位就在前面補 0 ): 0 0010 0000 1100 0011 0000 ,用這個比特流依次代替模板中的 x ,得到: 11110000 10100000 10110000 10110000 ,即 F0 A0 B0 B0 。
(
2
)
UTF-16
?UTF-16
編碼以
16
位無符號整數為單位。注意是
16
位為一個單位,不表示一個字符就只有
16
位。現在機器上的
unicode
編碼一般指的就是
UTF-16
。絕大部分
2
個字節就夠了,但是不能絕對的說所有字符都是
2
個字節。這個要看字符的
unicode
編碼處于什么范圍而定,有可能是
2
個字節,也可能是
4
個字節。這點請注意!
下面算法解釋來自百度百科。
我們把
Unicode?
unicode
編碼記作
U
。編碼規則如下:
如果
U<0x10000
,
U
的
UTF-16
編碼就是
U
對應的
16
位無符號整數(為書寫簡便,下文將
16
位無符號整數記作
WORD
)。
如果 U≥0x10000 ,我們先計算 U'=U-0x10000 ,然后將 U' 寫成二進制形式: yyyy yyyy yyxx xxxx xxxx , U 的 UTF-16 編碼(二進制)就是: 110110yyyyyyyyyy 110111xxxxxxxxxx 。為什么 U' 可以被寫成 20 個二進制位? Unicode 的最大碼位是 0x10ffff ,減去 0x10000 后, U' 的最大值是 0xfffff ,所以肯定可以用 20 個二進制位表示。
??? 例如: Unicode 編碼 0x20C30 ,減去 0x10000 后,得到 0x10C30 ,寫成二進制是: 0001 0000 1100 0011 0000 。用前 10
位依次替代模板中的 y ,用后 10 位依次替代模板中的 x ,就得到: 1101100001000011 1101110000110000 ,即 0xD843
0xDC30
。
???
按照上述規則,
Unicode
編碼
0x10000-0x10FFFF
的
UTF-16
編碼有兩個
WORD
,第一個
WORD
的高
6
位是
110110
,第二個
WORD
的高
6
位是
110111
。可見,第一個
WORD
的取值范圍(二進制)是
11011000 00000000
到
11011011 11111111
,即
0xD800-0xDBFF
。第二個
WORD
的取值范圍(二進制)是
11011100 00000000
到
11011111 11111111
,即
0xDC00-0xDFFF
。
為了將一個
WORD
的
UTF-16
編碼與兩個
WORD
的
UTF-16
編碼區分開來,
Unicode
編碼的設計者將
0xD800-0xDFFF
保留下來,并稱為代理區(
Surrogate
):
D800
-
DB7F
║
High Surrogates
║
高位替代
DB80
-
DBFF
║
High Private Use
Surrogates
║
高位專用替代
DC00
-
DFFF
║
Low Surrogates
║
低位替代
??
高位替代就是指這個范圍的碼位是兩個
WORD
的
UTF-16
編碼的第一個
WORD
。低位替代就是指這個范圍的碼位是兩個
WORD
的
UTF-16
編碼的第二個
WORD
。那么,高位專用替代是什么意思?我們來解答這個問題,順便看看怎么由
UTF-16
編碼推導
Unicode
編碼。
?
如果一個字符的
UTF-16
編碼的第一個
WORD
在
0xDB80
到
0xDBFF
之間,那么它的
Unicode
編碼在什么范圍內?我們知道第二個
WORD
的取值范圍是
0xDC00-0xDFFF
,所以這個字符的
UTF-16
編碼范圍應該是
0xDB80 0xDC00
到
0xDBFF 0xDFFF
。我們將這個范圍寫成二進制:
1101101110000000 11011100 00000000 - 1101101111111111
1101111111111111
按
照編碼的相反步驟,取出高低
WORD
的后
10
位,并拼在一起,得到
1110 0000
0000 0000 0000 - 1111 1111 1111 1111 1111?
即
0xe0000-0xfffff
,按照編碼的相反步驟再加上
0x10000
,得到
0xf0000-0x10ffff
。這就是
UTF-16
編碼的第一個
WORD
在
0xdb80
到
0xdbff
之間的
Unicode
編碼范圍,即平面
15
和平面
16
。因為
Unicode
標準將平面
15
和平面
16
都作為專用區,所以
0xDB80 到 0xDBFF 之間的保留碼位被稱作高位專用替代。
(
3
)
UTF-32
?
這個就簡單了,和
Unicode
碼表基本一一對應,固定四個字節。
?
為什么不采用
UTF-32
呢,因為
unicode
定義的范圍太大了,其實
99%
的人使用的字符編碼不會超過
2
個字節,所以如同統一用
4
個字節,簡單倒是簡單了,但是數據冗余確實太大了,不好,所以
16
位是最好的。就算遇到超過
16
位能表示的字符,我們也可以通過上面講到的代理技術,采用
32
位標識,這樣的方案是最好的。所以現在絕大部分機器實現
unicode
還是采用的 utf-16 的方案。當然也有 UTF-8 的方案。比如 windows 用的就是 UTF16 方案,不少 linux 用的就是 utf8 方案。
7. 編碼存儲差異
這里就要引出兩個名詞:
LE
(
little endian):
小字節字節序,意思就是一個單元在計算機中的存放時按照低位在前(低地址),高位在后(高地址)的模式存放。
BE ( big endian): 大字節字節序,和 LE 相反,是高位在前,低位在后。
比如一個
unicode
編碼為:
0x006C49
,如果是
LE
,那么在文件中的存放順序應該是:
49 6c 00
如果是
BE ,
那么順序應該是:
00 6c 49
8. 編碼格式的檢測
到底采用什么編碼,如果能檢測就好了。專家們也是這么想的,所以專家給每種格式和字節序規定了一些特殊的編碼,
這些編碼在 unicode 中是沒有使用的,所以不用擔心會沖突。
這個叫做
BOM
(
Byte Order
Mark
)頭。意思是字節序標志頭。通過它基本能確定編碼格式和字節序。
UTF
編碼
║
Byte Order Mark
UTF-8
???
║
EF BB BF
UTF-16LE
║
FF FE
UTF-16BE
║
FE FF
UTF-32LE
║
FF FE 00 00
UTF-32BE
║
?
00 00 FE FF
所以通過檢測文件前面的
BOM
頭,基本能確定編碼格式和字節序。
但是這個
BOM
頭只是建議添加,不是強制的,所以不少軟件和系統沒有添加這個
BOM
頭(所以有些軟件格式中有帶
BOM
頭和
NoBOM
頭的選擇),這個時候要檢測什么格式,就比較麻煩了當然可以檢測,但是不能保證
100%
準確,只能通過編碼范圍從概率上來檢查,雖然準確度還是比較高,但是不能保證
100%
。所以,時常看到檢測錯誤的軟件,也不奇怪了。
總結:
??
終于寫完了,其實這些問題都是不統一導致的,屬于歷史問題,所以才會有這些困惑,這里也呼吁所有的軟件
開發人員自覺的采用
Unicode
標準進行文字處理,我相信在不久的將來,這些困擾都不會存在了,因為所有軟件都是
unicode d ,
只要有字庫,任何文字都能同時顯示,也可以到任何語言的平臺上的去運行,不再有亂碼的困惑!其實現在絕大部分軟件已經是這么做的了!
??
另外也不要被很多名詞屬于所迷惑,其實這些只是標準的問題,根本沒有什么新的東西,更沒有什么復雜的東西。
?
摘自 http://blog.csdn.net/softman11/archive/2011/01/08/6124345.aspx
?
posted on 2011-08-19 00:20 Vcer-JZ 閱讀(428) 評論(0) 編輯 收藏 引用 所屬分類: MFC