轉自:https://blog.csdn.net/vgwciro8nu/article/details/60583186 首先來看一下常用的編碼有哪些,截圖自Notepad++。其中ANSI在中國大陸即為GBK(以前是GB2312),最常用的是 GBK 和 UTF8無BOM 編碼格式。后面三個都是有BOM頭的文本格式,UCS-2即為人們常說的Unicode編碼,又分為大端、小端。 所謂BOM頭(Byte Order Mark)就是文本文件中開始的幾個并不表示任何字符的字節,用二進制編輯器(如bz.exe)就能看到了。 UTF8的BOM頭為 0xEF 0xBB0xBF Unicode大端模式為 0xFE 0xFF Unicode小端模式為 0xFF 0xFE 何為GBK,何為GB2312,與區位碼有何淵源? 區位碼是早些年(1980)中國制定的一個編碼標準,如果有玩過小霸王學習機的話,應該會記得有個叫做“區位”的輸入法(沒記錯的話是按F4選擇)。就是打四個數字然后就出來漢字了,什么原理呢。請看下面的區位碼表,每一個字符都有對應一個編號。其中前兩位為“區”,后兩位為“位”,中文漢字的編號區號是從16開始的,位號從1開始。前面的區號有一些符號、數字、字母、注音符號(臺)、制表符、日文等等。 而GB2312編碼就是基于區位碼的,用雙字節編碼表示中文和中文符號。一般編碼方式是:0xA0+區號,0xA0+位號。如下表中的“安”,區位號是1618(十進制),那么“安”字的GB2312編碼就是0xA0+16 0xA0+18 也就是 0xB0 0xB2。根據區位碼表,GB2312的漢字編碼范圍是0xB0A1~0xF7FE 區位碼表節選 可能大家注意到了,區位碼里有英文和數字,按道理說是不是也應該是雙字節的呢。而一般情況下,我們見到的英文和數字是單字節的,以ASCII編碼,也就是說現代的GBK編碼是兼容ASCII編碼的。比如一個數字2,對應的二進制是0x32,而不是 0xA30xB2。那么問題來了,0xA3 0xB2 又對應到什么呢?還是2(笑)。注意看了,這里的2跟2是不是有點不太一樣?!確實是不一樣的。這里的雙字節2是全角的二,ASCII的2是半角的二,一般輸入法里的切換全角半角就是這里不同。 如果留意過早些年的手機(功能機),會發現人名中常見的“燊”字是打不出來的。為什么呢?因為早期的區位碼表里面并沒有這些字,也就是說早期的GB2312也是沒有這些字的。到后來的GBK(1995)才補充了大量的漢字進去,當然現在的安卓蘋果應該都是GBK字庫了。再看看這些補充的漢字的字節碼 燊 0x9F0xF6 。和前面說到的GB2312不同,有的字的編碼比 0xA0 0xA0 還小,難道新補充的區位號還能是負的??其實不然,這次的補充只補充了計算機編碼表,并沒有補充區位碼表。也就是說區位碼表并沒有更新,用區位碼打字法還是打不出這些字,而網上的反向區位碼表查詢也只是按照GBK的編碼計算,并不代表字與區位號完全對應。時代的發展,區位碼表早已經是進入博物館的東西了。 Big5是與GB2312同時期的一種臺灣地區繁體字的編碼格式。后來GBK編碼的制定,把Big5用的繁體字也包含進來(但編碼不兼容),還增加了一些其它的中文字符。細心的朋友可能還會發現,臺灣香港用的繁體字(如KTV里的字幕)跟大陸用的繁體字還有點筆畫上的不一樣,其實這跟編碼無關,是字體的不同,大陸一般用的是宋體楷體黑體,港澳臺常用的是明體(鳥哥Linux私房菜用的是新細明體)。GBK總體編碼范圍為0x8140~0xFEFE,首字節在0x81~0xFE 之間,尾字節在0x40~0xFE 之間,剔除 xx7F 一條線。詳細編碼表可以參考這個列表。微軟Windows安排給GBK的code page(代碼頁)是CP936,所以有時候看到編碼格式是CP936,其實就是GBK的意思。2000年和2005年,國家又先后兩次發布了GB18030編碼標準,兼容GBK,新增四字節的編碼,但比較少見。 同一個編碼文件里,怎么區分ASCII和中文編碼呢?從ASCII表我們知道標準ASCII只有128個字符,0~127即0x00~0x7F(0111 1111)。所以區分的方法就是,高字節的最高位為0則為ASCII,為1則為中文。 UTF8編碼與 Unicode編碼 GBK是中國標準,只在中國使用,并沒有表示大多數其它國家的編碼;而各國又陸續推出各自的編碼標準,互不兼容,非常不利于全球化發展。于是后來國際組織發行了一個全球統一編碼表,把全球各國文字都統一在一個編碼標準里,名為Unicode。很多人都很疑惑,到底UTF8與Unicode兩者有什么關系?如果要類比的話,UTF8相當于GB2312,Unicode相當于區位碼表,不同的是它們之間的編號范圍和轉換公式。那什么是原始的Unicode編碼呢?如果你用過PHP的話,json_encode函數默認會把中文編碼成為Unicode,比如“首發于博客園”就會轉碼成“\u9996\u53d1\u4e8e\u535a\u5ba2\u56ed”。可以看到每個字都變成了 \uXXXX 的形式,這個就是文字的對應Unicode編碼,\u表示Unicode的意思,網上也有用U+表示unicode。現行的Unicode編碼標準里,絕大多數程序語言只支持雙字節。英文字母、標點也收納在Unicode編碼中。有興趣的可以在站長工具里嘗試“中文轉Unicode”,可以得到你輸入文字的Unicode編碼。 因為英文字符也全部使用雙字節,存儲成本和流量會大大地增加,所以Unicode編碼大多數情況并沒有被原始地使用,而是被轉換編碼成UTF8。下表就是其轉換公式: 第一種:Unicode從 0x0000 到 0x007F 范圍的,是不是有點熟悉?對,其實就是標準ASCII碼里面的內容,所以直接去掉前面那個字節 0x00,使用其第二個字節(與ASCII碼相同)作為其編碼,即為單字節UTF8。 第二種:Unicode從 0x0080 到 0x07FF 范圍的,轉換成雙字節UTF8。 第三種:Unicode從 0x8000 到 0xFFFF 范圍的,轉換成三字節UTF8,一般中文都是在這個范圍里。 第四種:超過雙字節的Unicode目前還沒有廣泛支持,僅見emoji表情在此范圍。 例如“博”字的Unicode編碼是\u535a。0x535A在0x0800~0xFFFF之間,所以用3字節模板 1110yyyy 10yyyyxx 10xxxxxx。將535A寫成二進制是:01010011 0101 1010,高八位分別代替y,低八位分別代替x,得到 1110010110001101 10011010,也就是 0xE58D9A,這就是博字的UTF8編碼。 前面提到,GBK的編碼里英文字符有全角和半角之分,全角為GBK的標準編碼過的雙字節2,半角為ASCII的單字節2。那現在UTF8是全部用一個公式,理論上只有半角的2的,怎么支持全角的2呢?哈哈,結果是Unicode為中國特色的全角英文字符也單獨分配了編碼,簡單粗暴。比如全角的2的Unicode編碼是 \uFF12,轉換到UTF8就是 0xEFBC92。 文章開頭有說到 UCS-2,其實UCS-2就是原始的雙字節Unicode編碼,用二進制編輯器打開UCS-2大端模式的文本文件,從左往右看,看到的就是每個字符的Unicode編碼了。至于什么是大端小端,就是字節的存放順序不同,這一般是嵌入式編程的范疇。 如何區分一個文本是無BOM的UTF8還是GBK 前面說到的幾種編碼,其中有的是有BOM頭的,可以直接根據BOM頭區分出其編碼。有兩個是沒有BOM頭的,UTF8和GBK,那么兩者怎么區分呢?答案是,只能按大量的編碼分析來區分。目前識別準確率很高的有:Notepad++等一些常用的IDE,PHP的mb_系列函數,python的chardet庫及其它語言衍生版如jchardet,jschardet 等(請自行github)。 那么這些庫是怎么區分這些編碼的呢?那就是詞庫,你會看到庫的源碼里有大量的數組,其實就是對應一個編碼里的常見詞組編碼組合。同樣的文件字節流在一個詞組庫里的匹配程度越高,就越有可能是該編碼,判斷的準確率就越大。而文件中的中文越少越零散,判斷的準確率就越低。 關于ASCII 文中多次提及ASCII編碼,其實這應該是每個程序員都非常熟悉、認真了解的東西。對于嵌入式開發的人來說,應該能隨時在字符與ASCII碼中轉換,就像十六進制與二進制之間的轉換一樣。標準ASCII是128個,范圍是0x00~0x7F (0000 0000~0111 0000) ,最高位為0。也有一個擴展ASCII碼規則,把最高位也用上了,變成256個,但是這個擴展標準爭議很大,沒有得到推廣,應該以后不會得到推廣。因為無論是GBK還是UTF8,如果ASCII字符編碼最高位能為1都會造成混亂無法解析。 以GBK為例,如果ASCII的字符最高位也能是1,那么是應該截取一個解析為ASCII呢?還是截取兩個解析為中文字符?這根本無法判斷。UTF8也是同理,遇到 0xxx 開頭則截取一個(即為標準ASCII), 遇到 110x 開頭則截取兩個,遇到1110 開頭則截取三個,如果ASCII包含1開頭的,則無法確定何時截取多少個。 在哪里還能一睹擴展ASCII的真容呢?其實很簡單,只要把網頁的meta改成ASCII就行了 <meta charset="ASCII" /> 。又或者瀏覽器的編碼選擇“西方”,即可見到與平常所見不同的亂碼。(截圖為火狐) ———————————————— 版權聲明:本文為CSDN博主「VGWCIrO8NU」的原創文章,遵循 CC4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。 原文鏈接:https://blog.csdn.net/vgwciro8nu/article/details/60583186
|