【转】刨根究底字符编码之十三——UTF-16编码方式
1.
UTF-16編碼方式源于UCS-2(Universal Character Set coded in 2 octets、2-byte Universal Character Set)。而UCS-2,是早期遺留下來的歷史產(chǎn)物。
UCS-2將字符編號直接映射為字符編碼(CEF,而非CES,詳見前文中對現(xiàn)代字符編碼模型的解釋),亦即字符編號就是字符編碼,中間沒有經(jīng)過特別的編碼算法轉(zhuǎn)換。因此,從現(xiàn)代字符編碼模型的角度來看的話,此時并沒有將編號字符集CCS與字符編碼方式CEF作嚴(yán)格區(qū)分,既可以將UCS-2看作是編號字符集CCS中的字符編號,也可以看作是字符編碼方式CEF中的字符編碼。
后來,隨著Unicode聯(lián)盟與ISO/IEC就創(chuàng)建全球統(tǒng)一的單一通用字符集進(jìn)行合作,Unicode字符集與UCS字符集逐漸相互融合,兩者最終基本保持了一致(詳見前文《刨根究底字符編碼之八——Unicode編碼方案概述》中的介紹)。
(笨笨阿林原創(chuàng)文章,轉(zhuǎn)載請注明出處)
2.
這之后,Unicode逐漸占據(jù)了主導(dǎo)地位,并引入了UTF-16編碼方式。為什么要引入U(xiǎn)TF-16編碼方式呢?
前文已經(jīng)介紹過了,Unicode字符集(CCS)到目前為止定義了包括1個基本平面BMP和16個增補(bǔ)平面SP在內(nèi)的共17個平面。
每個平面的碼點(diǎn)數(shù)量為2^16=65536個,因此17個平面的碼點(diǎn)總數(shù)為共65536*17=1114112個。其中,基本平面碼點(diǎn)為65536個(碼點(diǎn)編號范圍為0x0000~0xFFFF),增補(bǔ)平面碼點(diǎn)為1114112-65536=65536*16=1048576個(碼點(diǎn)編號范圍為0x10000~0x10FFFF)。
很明顯,簡單地用一個16位碼元肯定無法表示所有17個平面的這么多碼點(diǎn)(因?yàn)?^16=65536,而碼點(diǎn)總數(shù)為65536*17=1114112)。而UCS-2,正是用兩個字節(jié)共16位來表示一個字符的。為支持字符編號超過U+FFFF的增補(bǔ)字符,擴(kuò)展勢在必行。
3.
UCS因而又提出了UCS-4,即用四個字節(jié)共32位來表示一個字符(此時UCS-4同樣既可認(rèn)為是編號字符集CCS中的字符編號,也可認(rèn)為是字符編碼方式CEF中的字符編碼)。但碼元也因此從16位擴(kuò)展到了32位。
而Unicode卻提出了不同的擴(kuò)展方式——代理機(jī)制。具體而言,就是為了能以一個統(tǒng)一的16位碼元同時編碼基本平面以及增補(bǔ)平面中的字符碼點(diǎn)編號,Unicode設(shè)計(jì)引入了UTF-16編碼方式,并且通過代理機(jī)制實(shí)現(xiàn)了擴(kuò)展。
UTF-16編碼方式的引入,從現(xiàn)代字符編碼模型的角度來看的話,徹底將編號字符集CCS與字符編碼方式CEF作了嚴(yán)格區(qū)分。也就是說,在UTF-16編碼方式中,編號字符集CCS中的字符編號與字符編碼方式CEF中的字符編碼不再僅僅是簡單的直接映射關(guān)系。
具體來說,就是Unicode字符集基本平面BMP中的字符(大致相當(dāng)于UCS字符集中的UCS-2字符,但必須除開U+D800~U+DFFF這一在Unicode字符集BMP中稱之為代理碼點(diǎn)的部分),仍然是直接映射關(guān)系,亦即這部分字符的字符編號與字符編碼是等同的。
但Unicode字符集增補(bǔ)平面中的字符(大致相當(dāng)于UCS字符集UCS-4字符中除開UCS-2字符的部分,因?yàn)閺V義上的UCS-4字符實(shí)際上包含了UCS-2字符,當(dāng)然狹義上的UCS-4字符不包括UCS-2字符),卻不是直接映射關(guān)系,而是必須通過代理機(jī)制這一編碼算法的轉(zhuǎn)換,亦即這部分字符的字符編號與字符編碼不是等同的。
因此,在Unicode引入了UTF-16編碼方式之后,站在現(xiàn)代字符編碼模型的角度上來看的話,再將UCS-2和UCS-4直接稱之為字符編碼方式CEF已不是很合適,更多的應(yīng)該是編號字符集CCS中的概念(當(dāng)然,在了解其歷史原因之后,將UCS-2和UCS-4同時理解為編號字符集CCS和字符編碼方式CEF也未嘗不可);而若將UCS-2等同于UTF-16,將UCS-4等同于UTF-32(后文會有介紹),顯然也是不合適的。
(笨笨阿林原創(chuàng)文章,轉(zhuǎn)載請注明出處)
4.
UTF-16中的所謂代理機(jī)制,實(shí)際上就是用兩個對應(yīng)于基本平面BMP代理區(qū)(Surrogate Zone)中的碼點(diǎn)編號的16位碼元來表示一個增補(bǔ)平面碼點(diǎn),這兩個用來表示一個增補(bǔ)平面碼點(diǎn)的特殊16位碼元被稱之為代理對(Surrogate Pair)(解釋詳見后文《UTF-16究竟是如何編碼的——UTF-16的編碼算法詳解》)
UTF-16編碼方式及其代理機(jī)制是在Unicode 2.0中為支持字符編號超過U+FFFF的增補(bǔ)字符而引入的,于是從此就由UCS-2的等寬(16位)碼元序列編碼方式(如前文所述,從現(xiàn)代字符編碼模型的角度來看的話,UCS-2更多是的編號字符集CCS中的概念,但考慮到其歷史原因,稱之為字符編碼方式CEF亦未嘗不可,下同,不再贅述),變成了UTF-16的變寬(16位或32位)碼元序列編碼方式。不過,碼元依然保持了16位不變。
5.
UCS-2所編碼的字符集中的U+D800~U+DFFF這部分代理碼點(diǎn)除外的話,UTF-16所編碼的字符集可看成是UCS-2所編碼的字符集的父集。
在沒有引入增補(bǔ)平面字符之前,UTF-16與UCS-2(U+D800~U+DFFF這部分代理碼點(diǎn)除外)的編碼完全相同。但當(dāng)引入增補(bǔ)平面字符后,UTF-16與UCS-2的編碼就不完全相同了(事實(shí)上,由于UCS-2只有兩個字節(jié),根本無法編碼增補(bǔ)平面字符)。
現(xiàn)在若有軟件聲稱自己支持UCS-2編碼,那相當(dāng)于是在暗示其僅支持UCS字符集或Unicode字符集中的基本平面字符,而不能支持增補(bǔ)平面字符。
6.
所以說,UTF-16是變長編碼方式,每個字符編碼為16位或32位;而UCS-2是定長編碼方式,每個字符編碼固定為16位。但兩者的碼元卻都是16位的(而UTF-32和狹義的UCS-4的碼元都是32位的)。
另外,UTF-16中,大部分漢字采用兩個字節(jié)編碼,少量不常用漢字采用四個字節(jié)編碼。
Windows 2000及之后的版本是支持UTF-16的,之前的Windows NT/95/98/ME是只支持UCS-2的。
(笨笨阿林原創(chuàng)文章,轉(zhuǎn)載請注明出處)
7.
作為邏輯意義上的UTF-16編碼(碼元序列),由于歷史的原因,在映射為物理意義上的字節(jié)序列時,分為UTF-16BE(Big Endian)、UTF-16LE(Little Endian)兩種情況。比如,“ABC”這三個字符的UTF-16編碼(碼元序列)為:00 41 00 42 00 43;其對應(yīng)的各種字節(jié)序列如下:
Windows平臺下的UTF-16編碼(即上述的FF FE 41 00 42 00 43 00) 默認(rèn)為帶有BOM的小端序(即Little Endian with BOM)。你可以打開記事本,寫上ABC,保存時選擇Unicode(這里的Unicode實(shí)際上指的是UTF-16 Little Endian with BOM,即帶BOM的UTF-16小端序CES編碼,詳見后文解釋)
然后保存,再用UltraEdit編輯器看看它的編碼結(jié)果:
Windows從NT時代開始就采用了UTF-16編碼方式,很多流行的編程平臺,例如.Net、Java、Qt還有Mac下的Cocoa等都是使用UTF-16作為基礎(chǔ)的字符編碼。例如代碼中的字符串,在內(nèi)存中相應(yīng)的字節(jié)流就是UTF-16字節(jié)序列的。(注意,UTF-16編碼在Windows環(huán)境中被誤用為“widechar”和“Unicode”的同義詞)
8.
UTF-16一方面使用變長碼元序列的編碼方式,相較于定長碼元序列的UTF-32算法更復(fù)雜(甚至比同樣是變長碼元序列的UTF-8也更為復(fù)雜,因?yàn)橐肓霜?dú)特的代理對這樣的代理機(jī)制);另一方面仍然占用過多字節(jié),比如ASCII字符也同樣需要占用兩個字節(jié),相較于UTF-8更浪費(fèi)空間和帶寬。
因此,UTF-16在Unicode字符集的三大編碼方式(UTF-8、UTF-16、UTF-32)中表現(xiàn)較為糟糕。它的存在是歷史原因造成的,引起了很多混亂。不過由于其推出時間最早,已被應(yīng)用于大量環(huán)境中,目前雖然不被推薦使用,但長期來看,作為程序人員都不得不與之打交道。因而,對于其具體的編碼算法的了解是十分必要的,本系列文章的下一篇將詳細(xì)介紹其復(fù)雜的編碼算法(主要是代理編碼算法)。
(笨笨阿林原創(chuàng)文章,轉(zhuǎn)載請注明出處)
(未完待續(xù))
總結(jié)
以上是生活随笔為你收集整理的【转】刨根究底字符编码之十三——UTF-16编码方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转】Postman系列一:Postma
- 下一篇: 皮卡销量又跌了:五菱蔫得抬不起头