需要再一次強(qiáng)調(diào)的是,無論歷的UCS還是現(xiàn)如今的Unicode,兩者指的都是編碼字符集,而不是字符集編碼?;ㄙM(fèi)一點(diǎn)時(shí)間來理解好這件事,然后你會發(fā)現(xiàn)對所有網(wǎng)頁的,系統(tǒng)的,編碼標(biāo)準(zhǔn)之間的來回轉(zhuǎn)換等等繁雜事務(wù)都會思路清晰,手到擒來。
首先說說最一般意義上的字符集。
一個(gè)抽象字符集其實(shí)就是指字符的集合,例如所有的英文字母是一個(gè)抽象字符集,所有的漢字是一個(gè)抽象字符集,當(dāng)然,把全世界所有語言的符號都放在一起,也可以稱為一個(gè)抽象字符集,所以這個(gè)劃分是相當(dāng)人為的。之所以說“抽象”二字,是因?yàn)檫@里所提及的字符不是任何具體形式的字符,拿漢字中的“漢”這個(gè)字符來說,您在這篇文章中看到的這個(gè)“漢”其實(shí)是這個(gè)字符的一種具體表現(xiàn)形式,是它的圖像表現(xiàn)形式,而且它是用中文(而非拼音)書寫而成,使用微軟雅黑外觀;而當(dāng)人們用嘴發(fā)出“漢”這個(gè)音的時(shí)候,他們是在使用“漢”的另一種具體表現(xiàn)形式——聲音,但無論如何,兩者所指的字符都是“漢”這個(gè)字。同一個(gè)字符的表現(xiàn)形式可能有無數(shù)種(點(diǎn)陣表示,矢量表示,音頻表示,楷體,草書等等等等),把每一種表現(xiàn)形式下的同一個(gè)字符都納入到字符集中,會使得集合過于龐大,冗余高,也不好管理。因此抽象字符集中的字符,都是指存在的抽象字符,而忽略它的具體表現(xiàn)形式。
抽象字符集中的諸多字符,沒有順序之分,誰也不能說哪個(gè)字符在哪個(gè)字符前面,而且這種抽象字符只有人能理解。在給一個(gè)抽象字符集合中的每個(gè)字符都分配一個(gè)整數(shù)編號之后(注意這個(gè)整數(shù)并沒有要求大?。?,這個(gè)字符集就有了順序,就成為了編碼字符集。同時(shí),通過這個(gè)編號,可以確定到底指的是哪一個(gè)字符。當(dāng)然,對于同一個(gè)字符,不同的字符集編碼系統(tǒng)所制定的整數(shù)編號也不盡相同,例如“兒”這個(gè)字,在Unicode中,它的編號是0x513F,(為方便起見,以十六進(jìn)制表示,但這個(gè)整數(shù)編號并不要求必須是以十六進(jìn)制表示)意思是說它是Unicode這個(gè)編碼字符集中的第0x513F個(gè)字符。而在另一種編碼字符集比如Big5中,這個(gè)字就是第0xA449個(gè)字符了。這種情況的另一面是,許多字符在不同的編碼字符集中被分配了相同的整數(shù)編號,例如英文字母“A”,在ASCII及Unicode中,均是第0x41個(gè)字符。我們常說的Unicode字符集,指的就是這種被分配了整數(shù)編號的字符集合,但要澄清的是,編碼字符集中字符被分配的整數(shù)編號,不一定就是該字符在計(jì)算機(jī)中存儲時(shí)所使用的值,計(jì)算機(jī)中存儲的字符到底使用什么二進(jìn)制整數(shù)值來表示,是由下面將要說到的字符集編碼決定的。
字符集編碼決定了如何將一個(gè)字符的整數(shù)編號對應(yīng)到一個(gè)二進(jìn)制的整數(shù)值,有的編碼方案簡單的將該整數(shù)值直接作為其在計(jì)算機(jī)中的表示而存儲,例如英文字符就是這樣,幾乎所有的字符集編碼方案中,英文字母的整數(shù)編號與其在計(jì)算機(jī)內(nèi)部存儲的二進(jìn)制形式都一致。但有的編碼方案,例如適用于Unicode字符集的UTF-8編碼形式,就將很大一部分字符的整數(shù)編號作了變換后存儲在計(jì)算機(jī)中。以“漢”字為例,“漢”的Unicode值為0x6C49,但其編碼為UTF-8格式后的值為0xE6B189(注意到變成了三個(gè)字節(jié))。這里只是舉個(gè)例子,關(guān)于UTF-8的詳細(xì)編碼規(guī)則可以參看《Mapping codepoints to Unicode encoding forms》一文,URL為http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-AppendixA#sec3.我們經(jīng)常聽說的另一種編碼方案UTF-16,則對Unicode中的前65536個(gè)字符編號都不做變換,直接作為計(jì)算機(jī)存儲時(shí)使用的值(對65536以后的字符,仍然要做變換),例如“漢”字的Unicode編號為0x6C49,那么經(jīng)過UTF-16編碼后存儲在計(jì)算機(jī)上時(shí),它的表示仍為0x6C49!。我猜,正是因?yàn)閁TF-16的存在,使得很多人認(rèn)為Unicode是一種編碼(實(shí)際上,是一個(gè)字符集,再次重申),也因此,很多人說Unicode的時(shí)候,他們實(shí)際上指的是UTF-16.UTF-16提供了surrogate pair機(jī)制,使得Unicode中碼位大于65536的那些字符得以表示。
Surrogate pair機(jī)制在目前來說實(shí)在不常用,甚至連一些UTF-16的實(shí)現(xiàn)都不支持,所以我不打算在這里多加討論,其基本的思想就是用兩個(gè)16位的編碼表示一個(gè)字符(注意,只對碼位超過65536的字符這么做)。Unicode如此死抱著16這個(gè)數(shù)字不放,有歷史的原因,也有實(shí)用的原因。
當(dāng)然還有一種的編碼,UTF-32,他對所有的Unicode字符均不做變換,直接使用編號存儲?。ㄋ追Q的以不變應(yīng)萬變),只是這種編碼方案太浪費(fèi)存儲空間(就連1個(gè)字節(jié)就可以搞定的英文字符,它都必須使用4個(gè)字節(jié)),因而盡管使用起來方便(不需要任何轉(zhuǎn)換),卻沒有得到普及。
記得當(dāng)初Unicode與UCS還沒成家之時(shí),UCS也是需要人愛,需要人疼的,沒有自己的字符集編碼怎么成。UCS-2與UCS-4就扮演了這樣的角色。UCS-4與UTF-32除了名字不同以外,思想完全一樣。而UCS-2與UTF-16在對前65536個(gè)字符的處理上也完全相同,的區(qū)別只在于UCS-2 不支持surrogate pair機(jī)制,即是說,UCS-2只能對前65536個(gè)字符編碼,對其后的字符毫無辦法。不過現(xiàn)在再談起字符編碼的時(shí)候,UCS-2與UCS-4早已成為計(jì)算機(jī)史學(xué)家才會用到的詞匯,就讓它們繼續(xù)留在故紙堆里吧。
首先說說最一般意義上的字符集。
一個(gè)抽象字符集其實(shí)就是指字符的集合,例如所有的英文字母是一個(gè)抽象字符集,所有的漢字是一個(gè)抽象字符集,當(dāng)然,把全世界所有語言的符號都放在一起,也可以稱為一個(gè)抽象字符集,所以這個(gè)劃分是相當(dāng)人為的。之所以說“抽象”二字,是因?yàn)檫@里所提及的字符不是任何具體形式的字符,拿漢字中的“漢”這個(gè)字符來說,您在這篇文章中看到的這個(gè)“漢”其實(shí)是這個(gè)字符的一種具體表現(xiàn)形式,是它的圖像表現(xiàn)形式,而且它是用中文(而非拼音)書寫而成,使用微軟雅黑外觀;而當(dāng)人們用嘴發(fā)出“漢”這個(gè)音的時(shí)候,他們是在使用“漢”的另一種具體表現(xiàn)形式——聲音,但無論如何,兩者所指的字符都是“漢”這個(gè)字。同一個(gè)字符的表現(xiàn)形式可能有無數(shù)種(點(diǎn)陣表示,矢量表示,音頻表示,楷體,草書等等等等),把每一種表現(xiàn)形式下的同一個(gè)字符都納入到字符集中,會使得集合過于龐大,冗余高,也不好管理。因此抽象字符集中的字符,都是指存在的抽象字符,而忽略它的具體表現(xiàn)形式。
抽象字符集中的諸多字符,沒有順序之分,誰也不能說哪個(gè)字符在哪個(gè)字符前面,而且這種抽象字符只有人能理解。在給一個(gè)抽象字符集合中的每個(gè)字符都分配一個(gè)整數(shù)編號之后(注意這個(gè)整數(shù)并沒有要求大?。?,這個(gè)字符集就有了順序,就成為了編碼字符集。同時(shí),通過這個(gè)編號,可以確定到底指的是哪一個(gè)字符。當(dāng)然,對于同一個(gè)字符,不同的字符集編碼系統(tǒng)所制定的整數(shù)編號也不盡相同,例如“兒”這個(gè)字,在Unicode中,它的編號是0x513F,(為方便起見,以十六進(jìn)制表示,但這個(gè)整數(shù)編號并不要求必須是以十六進(jìn)制表示)意思是說它是Unicode這個(gè)編碼字符集中的第0x513F個(gè)字符。而在另一種編碼字符集比如Big5中,這個(gè)字就是第0xA449個(gè)字符了。這種情況的另一面是,許多字符在不同的編碼字符集中被分配了相同的整數(shù)編號,例如英文字母“A”,在ASCII及Unicode中,均是第0x41個(gè)字符。我們常說的Unicode字符集,指的就是這種被分配了整數(shù)編號的字符集合,但要澄清的是,編碼字符集中字符被分配的整數(shù)編號,不一定就是該字符在計(jì)算機(jī)中存儲時(shí)所使用的值,計(jì)算機(jī)中存儲的字符到底使用什么二進(jìn)制整數(shù)值來表示,是由下面將要說到的字符集編碼決定的。
字符集編碼決定了如何將一個(gè)字符的整數(shù)編號對應(yīng)到一個(gè)二進(jìn)制的整數(shù)值,有的編碼方案簡單的將該整數(shù)值直接作為其在計(jì)算機(jī)中的表示而存儲,例如英文字符就是這樣,幾乎所有的字符集編碼方案中,英文字母的整數(shù)編號與其在計(jì)算機(jī)內(nèi)部存儲的二進(jìn)制形式都一致。但有的編碼方案,例如適用于Unicode字符集的UTF-8編碼形式,就將很大一部分字符的整數(shù)編號作了變換后存儲在計(jì)算機(jī)中。以“漢”字為例,“漢”的Unicode值為0x6C49,但其編碼為UTF-8格式后的值為0xE6B189(注意到變成了三個(gè)字節(jié))。這里只是舉個(gè)例子,關(guān)于UTF-8的詳細(xì)編碼規(guī)則可以參看《Mapping codepoints to Unicode encoding forms》一文,URL為http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-AppendixA#sec3.我們經(jīng)常聽說的另一種編碼方案UTF-16,則對Unicode中的前65536個(gè)字符編號都不做變換,直接作為計(jì)算機(jī)存儲時(shí)使用的值(對65536以后的字符,仍然要做變換),例如“漢”字的Unicode編號為0x6C49,那么經(jīng)過UTF-16編碼后存儲在計(jì)算機(jī)上時(shí),它的表示仍為0x6C49!。我猜,正是因?yàn)閁TF-16的存在,使得很多人認(rèn)為Unicode是一種編碼(實(shí)際上,是一個(gè)字符集,再次重申),也因此,很多人說Unicode的時(shí)候,他們實(shí)際上指的是UTF-16.UTF-16提供了surrogate pair機(jī)制,使得Unicode中碼位大于65536的那些字符得以表示。
Surrogate pair機(jī)制在目前來說實(shí)在不常用,甚至連一些UTF-16的實(shí)現(xiàn)都不支持,所以我不打算在這里多加討論,其基本的思想就是用兩個(gè)16位的編碼表示一個(gè)字符(注意,只對碼位超過65536的字符這么做)。Unicode如此死抱著16這個(gè)數(shù)字不放,有歷史的原因,也有實(shí)用的原因。
當(dāng)然還有一種的編碼,UTF-32,他對所有的Unicode字符均不做變換,直接使用編號存儲?。ㄋ追Q的以不變應(yīng)萬變),只是這種編碼方案太浪費(fèi)存儲空間(就連1個(gè)字節(jié)就可以搞定的英文字符,它都必須使用4個(gè)字節(jié)),因而盡管使用起來方便(不需要任何轉(zhuǎn)換),卻沒有得到普及。
記得當(dāng)初Unicode與UCS還沒成家之時(shí),UCS也是需要人愛,需要人疼的,沒有自己的字符集編碼怎么成。UCS-2與UCS-4就扮演了這樣的角色。UCS-4與UTF-32除了名字不同以外,思想完全一樣。而UCS-2與UTF-16在對前65536個(gè)字符的處理上也完全相同,的區(qū)別只在于UCS-2 不支持surrogate pair機(jī)制,即是說,UCS-2只能對前65536個(gè)字符編碼,對其后的字符毫無辦法。不過現(xiàn)在再談起字符編碼的時(shí)候,UCS-2與UCS-4早已成為計(jì)算機(jī)史學(xué)家才會用到的詞匯,就讓它們繼續(xù)留在故紙堆里吧。