要把 UTF-8 說清楚,引入一個表會更方便了:
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
要看懂這個表呢,我們看前兩行就夠了
U-00000000 – U-0000007F: 0xxxxxxx 第一行是這樣的,意思是說,如果你發(fā)現(xiàn)一個utf-8編碼的 byte 的二進制碼是0xxxxxxx,是0開頭的, 即十進制的0-127之間,那么他就是單獨的這一 byte 代表一個字符,而且是擁有和 ascii 碼完全一樣的含義。其他所有的 utf8 編碼的二進制值都是用1開頭的1xxxxxxx,大于127的,而且都需要至少2 bytes才能代表一個符號。所以一個字節(jié)的第一位是一個開關,代表這個字符是不是一個 ascii 碼。這個就是剛才談到的兼容性,從英文定義上看,就是utf8編碼的兩個屬性:
UCS characters U+0000 to U+007F (ASCII) are encoded simply as bytes 0×00 to 0×7F (ASCII compatibility). This means that files and strings which contain only 7-bit ASCII characters have the same encoding under both ASCII and UTF-8. All UCS characters >U+007F are encoded as a sequence of several bytes, each of which has the most significant bit set. Therefore, no ASCII byte (0×00-0×7F) can appear as part of any other character.
然后我們看看第二行:
U-00000080 – U-000007FF: 110xxxxx 10xxxxxx 先看第一個字節(jié):110xxxxx,它的含義是,我不是一個 ascii 碼(因為第一位不為0),我是一個多 bytes 字符的第一個 byte (第二位為1),我參與表示的這個字符是由2個 bytes 組成的(第三位為0),從第四位開始,就是字符的信息儲存的位置。 再看第二個字節(jié):10xxxxxx,它的含義是:我不是一個 ascii 碼(因為第一位不為0),我不是一個多 bytes 字符的第一個 byte (第二位為0),第三位開始是字符的信息儲存的位置。
從這個例子中可以總結出來,utf-8編碼方式中,在一長串連續(xù)的二進制 byte 碼中,可能由2個至6個 bytes 來表示一個符號,那么相比較于用一個 byte 表示符號的 ascii 碼,我們需要空間來儲存兩個額外信息: 一,這個符號開始位置,一個“starter”的位置,用生物學上的話來說,就是蛋白質翻譯時候起始密碼子AUG的位置了;二,這個符號使用的 bytes 數(shù)(其實如果每個符號都有 starter,這個長度是可以不提供的,但是提供長度信息增加了在部分 bytes 丟失時的容錯能力)。解決方案是:用一個 byte 的第二位是否是1來代表這一 byte 是否是一個字符的起始 byte (因為一個 byte 里面的第一位剛才已經(jīng)被使用了,0表示ascii碼,1表示非ascii ),即,一個多字節(jié)符號的第一 個bytes一定是 11xxxxxx,一個192到255之間的二進制數(shù)。接下來,從第三位開始,提供長度信息,第三位是0表示這個符號是2字節(jié)的,第三位開始每多一個1,字符占用的 bytes 數(shù)加一。utf-8 最多定義到了 6 字節(jié)字符,需要比 110xxxxx 這樣的表示2字節(jié)的starter多 4 個 1,所以這個starter就是 1111110x,如上表所示。 再看看英文定義的標準吧,表達的同樣的意思:
The first byte of a multibyte sequence that represents a non-ASCII character is always in the range 0xC0 to 0xFD and it indicates how many bytes follow for this character. All further bytes in a multibyte sequence are in the range 0×80 to 0xBF. This allows easy resynchronization and makes the encoding stateless and robust against missing bytes.
真正的信息位(即,真正的charset字符集中的數(shù)字信息),是直接用二進制的方式,依順序放在上面這個表的’x'上的。用我們中國程序員接觸最多的漢字來說吧,它們的編碼區(qū)間是在 U-00000800 – U-0000FFFF 之間的,從上面的表中可以查到,這個區(qū)間的 utf-8 編碼是用三個字節(jié)來表示的(這就是 utf-8 編碼的漢字會比每個字符占用2 bytes的 EUC-CN 編碼的 gb2312 字符集的漢字使用更多儲存空間的原因),還是用 口碑的”口”字舉例吧,口字在 Unicode 中的編號是這樣的: 口: 21475 == 0×53e3 == 二進制 101001111100011
在 javascript 中,run這段代碼(使用 firebug 的 console,或者編輯一個HTML將下列代碼插入一對 script 標簽之間):
alert(’\u53e3′); //get ‘口’ alert(escape(’口’)); // get ‘%u53E3′ alert(String.fromCharCode(’21475′)); // get ‘口’ alert(’口’.charCodeAt(0)); // get ’21475‘ alert(encodeURI(’口’)); //get ‘%E5%8F%A3′
可以看到,string直接量可以用\u+十六進制 Unicode 碼的形式得到字符 ‘口’,而fromCharCode 方法接受 10 進制的 Unicode 碼,得到字符 ‘口’。
其中第二個alert得到的是 ‘%u7545′ , 這是一種不標準的Unicode編碼,是屬于 URI 的 Percent encoding 一部分,但這種使用方法已經(jīng)正式被 W3C 拒絕了,任何一個 RFC中都沒有這個標準,ECMA-262 標準中規(guī)定了 escape 的這種行為,估計也是暫時的。 比較有意思的是第五次alert得到的 ‘%E5%8F%A3′ 這是什么呢?怎么得到的呢?
這就是在URI上用的比較多的 Percent encoding,百分號編碼,RFC 3986 標準中規(guī)定的。
出處:口碑網(wǎng)UED Team
責任編輯:bluehearts
上一頁 HTML與javascript中常用編碼淺析 [1] 下一頁 HTML與javascript中常用編碼淺析 [3]
◎進入論壇網(wǎng)頁制作、WEB標準化版塊參加討論,我還想發(fā)表評論。
|