posts - 19, comments - 1, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
          [概述]
          ????? 在Windows操作系統(tǒng)中使用記事本新建一個(gè)文本文件,在文件里面寫入“聯(lián)通”兩個(gè)字并保存。當(dāng)再次打開這個(gè)文本文件時(shí)候,在記事本中看到得卻不是剛剛輸入的“聯(lián)通”,而是亂碼。網(wǎng)絡(luò)上有人把這個(gè)奇怪現(xiàn)象包裝成把戲,如果你曾遇到過這種把戲就會(huì)知道,他們往往讓你建立兩個(gè)文本文件進(jìn)行對(duì)比,其中一個(gè)輸入“聯(lián)通”,另外一個(gè)可能是“移動(dòng)”等等,最后試圖八卦地讓你相信聯(lián)通、移動(dòng)和微軟之間有著種種恩怨情仇。

          [解釋]
          ????? 這是一個(gè)字符編碼應(yīng)用的奇怪現(xiàn)象,講的明白點(diǎn),可以說是記事本開小差了!記事本為什么會(huì)犯錯(cuò)誤?記事本犯了怎樣的錯(cuò)誤呢?也許你會(huì)迫不及待的想知道這些問題,如果是這樣,我不會(huì)讓你空腹而歸的。
          ????? 在簡(jiǎn)體中文操作系統(tǒng)中默認(rèn)的本地字符集編碼是GBK編碼,除非你在保存記事本文本文件時(shí)候選擇了其他編碼方式,否則用記事本錄入的字符信息將使用GBK編碼進(jìn)行儲(chǔ)存。巧合的是,“聯(lián)通”這兩個(gè)字符的GBK編碼具有UTF-8編碼的特征,記事本犯下的錯(cuò)誤正是將GBK編碼存放的記錄有“聯(lián)通”兩個(gè)字符的文件誤認(rèn)為UTF-8編碼的文件。或許你會(huì)問,UTF-8編碼的文件不是以“EF BB BF”三個(gè)特殊字節(jié)開頭嗎?既然這樣,記事本怎么會(huì)犯這么低級(jí)的錯(cuò)誤呢?沒錯(cuò),UTF-8編碼規(guī)定使用UTF-8編碼的文件以“EF BB BF”三個(gè)特殊字節(jié)開頭,但并不是強(qiáng)制性要求,早期的UTF-8編碼文件就不遵循這個(gè)規(guī)定。因此記事本不能依靠文件的開頭字節(jié)判斷一個(gè)文件是否是UTF-8編碼,而只能對(duì)文件中的數(shù)據(jù)進(jìn)行簡(jiǎn)單的編碼分析來確定。正是這個(gè)原因,才有了字符編碼應(yīng)用中的這個(gè)奇怪又無法避免的現(xiàn)象。

          [細(xì)節(jié)]
          ????? 如果上面的解釋對(duì)于你來說只是杯開胃紅酒,那我還是塊點(diǎn)把主食呈上吧,一份大峽谷香烤豬肋排。UTF-8編碼采用1-3個(gè)字節(jié)對(duì)字符進(jìn)行編碼,編碼字節(jié)數(shù)與字符的Unicode編碼值有嚴(yán)格的對(duì)應(yīng)關(guān)系,讓我們回憶下UTF-8編碼和Unicode的對(duì)應(yīng)關(guān)系吧。

          ????? Unicode編碼值???????????????????????????? ?UTF-8編碼結(jié)構(gòu)
          ????? \u0001 - \u007E?????????????????????????? 0XXXXXXX
          ????? \u0080 - \u07FF 和 \u0000?????????? ?110XXXXX 10XXXXXX
          ????? \u0800 - \uFFFF??????????????????????????? 1110XXXX 10XXXXXX 10XXXXXX

          ????? “聯(lián)通”這兩個(gè)字符的GBK編碼值是“C1 AA CD A8",GBK編碼方式使用兩個(gè)字節(jié)對(duì)一個(gè)字符進(jìn)行編碼,因此以GBK編碼方式存放的錄有“聯(lián)通”兩個(gè)字符的文件的大小為四個(gè)字節(jié)。接下來分別觀察“聯(lián)通”這兩個(gè)字符GBK編碼值的二進(jìn)制形式,你有發(fā)現(xiàn)有趣的事。

          ????? 聯(lián)??? GBK??? 十六進(jìn)制:C1 AA??? 二進(jìn)制:1100 0001,1010 1010
          ????? 通??? GBK??? 十六進(jìn)制:C1 AA??? 二進(jìn)制:1100 1101,1010 1000

          ????? 請(qǐng)注意上面二進(jìn)制數(shù)據(jù)的著色部分,你想到了什么?對(duì),它們和UTF-8編碼結(jié)構(gòu)中的補(bǔ)充位完全一致,UTF-8編碼的補(bǔ)充位使得編碼值更有規(guī)律,而記事本剛好憑借這個(gè)特征區(qū)分UTF-8編碼的文件。存有“聯(lián)通”兩個(gè)字符的文件的所有數(shù)據(jù)都符合這個(gè)特征,就是這樣,記事本徹底的將文件誤認(rèn)為UTF-8編碼的文件。
          ????? 將錯(cuò)就錯(cuò),讓我們來看看這個(gè)錯(cuò)誤是怎樣收?qǐng)龅摹H绻选奥?lián)通”的GBK編碼值當(dāng)作UTF-8編碼值,那文件就成為一個(gè)寫有數(shù)據(jù)“C1 AA CD A8”并以UTF-8編碼的文件,當(dāng)使用記事本再次打開的時(shí)候會(huì)看到什么呢?只要將UTF-8編碼轉(zhuǎn)換成Unicode編碼就知道了。UTF-8編碼“C1 AA CD A8”轉(zhuǎn)換成Unicode編碼后,編碼值為“6A 00 68 03”(轉(zhuǎn)換方法請(qǐng)參考本Blog中的《字符編碼》一文)。0x006A這個(gè)Unicode編碼值位于\u0001 - \u007E之間,若要轉(zhuǎn)換為UTF-8編碼,顯然只能用一個(gè)字節(jié)進(jìn)行編碼,因此“聯(lián)”的GBK編碼“C1 AA”雖然特征上貌似UTF-8編碼,但它卻不對(duì)應(yīng)任何一個(gè)UTF-8編碼。接著看0x0368這個(gè)Unicode編碼值,這個(gè)值對(duì)應(yīng)了字符“?”,這也正是我們將在記事本中看到的內(nèi)容。或許你會(huì)說我看到的是一個(gè)黑色矩形啊,這只是字體的原因,你將字體改為宋體或者其他字體,看到的就是字符“?”。
          ????? 對(duì)于中文字符,UTF-8編碼要用三個(gè)字節(jié)進(jìn)行編碼,因此,如果你使用記事本錄入“聯(lián)通”,然后選擇以UTF-8編碼方式保存的話,文件大小應(yīng)為9個(gè)字節(jié)(包含三個(gè)字節(jié)的開頭數(shù)據(jù)),而同樣的文件GBK編碼卻是4個(gè)字節(jié)。最后附上“聯(lián)通”的GBK、UTF-8、Unicode編碼值,以及記事本的錯(cuò)誤思維。

          ????? 聯(lián)通??GBK? C1 AA CD A8??? UTF-8? E8 81 94 E9 80 9A??? Unicode? 54 80 1A 90
          ????? 聯(lián)通? GBK? C1 AA CD A8??? UTF-8? C1 AA CD A8????????????Unicode? 6A 00 68 03? (將GBK值誤認(rèn)為UTF-8值的結(jié)果)

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 乌兰察布市| 临泽县| 丹东市| 宜黄县| 晋中市| 海宁市| 奉化市| 襄城县| 辉南县| 卢龙县| 南木林县| 沙湾县| 中方县| 娱乐| 安顺市| 石台县| 延庆县| 来安县| 贡觉县| 遵化市| 广昌县| 雷山县| 收藏| 微山县| 普兰县| 洮南市| 岱山县| 桑植县| 鸡泽县| 榆社县| 双鸭山市| 宁乡县| 大渡口区| 桂林市| 文昌市| 蒙城县| 巍山| 兴山县| 平陆县| 同心县| 新野县|