折
磨人的編碼
“
編碼問題就像蛀牙一樣——平時不曾注意,直到他給你造成成噸傷害。
”
本期大貓將開個新帖介紹R中的編碼問題。就像導言中說的,編碼是一個常常被忽視的“小問題”——直到他給你造成成噸的傷害Orz。它尤其頻繁出現于數據傳輸中,例如你在澳大利亞的機器上建立的SAS數據集死活沒法在中國的SAS中打開,或是R 操作臺打印中文總是亂碼等等(關于中文編碼請閱讀大貓上一期《我知道你不知道GB2312》)。大貓新開這個系列的目的就是幫助大家在最短時間搞明白你所要知道的關于編碼的一切。最重要的是,這篇文章不會過于詳細的探討這些編碼背后的原理,而是明確告訴大家在什么樣的時候應該用什么樣的編碼(相信這是大家最希望了解的)。至于這些編碼背后的復雜原理以及歷史,大貓會在最后放上鏈接,有興趣的小伙伴可以自行閱讀。由于盡量追求通俗易懂,下面內容可能無法在技術上保證100%的嚴謹,但是大貓保證,以下95%的論述都是正確的!
今天的文章分成兩部分,第一部分介紹常見的編碼格式,包括ASCII,ANSI,UTF-8,是后面所有內容的基礎;第二部分講解這些編碼在Windows中的版本——Code page。在下一期中,大貓將著重講解Windows平臺下R的編碼系統。
對于特別沒有耐心的小伙伴,在這里先放上結論:
ASCII是個古董,能表示的字符最少,且不能表示中文,幾乎被淘汰。后來所有新的編碼都兼容ASCII;ANSI是ASCII的擴展,由國際標準組織(ISO)定義,且每個語言都有一套自己的ANSI編碼體系,西文中最常用的那個版本叫 ISO-8895-1 (Latin-1),也是R所支持的三大編碼之一;簡體中文常見ANSI類型編碼有GB2312、GBK和GB18030;Windows把ISO標準的ANSI編碼稱為“代碼頁”(Code page,CP)其中ISO-8895-1 (Latin-1)被稱為CP-1252,簡中編碼GBK被稱為CP-936。Unicode是一類代碼的統稱,是出現最晚、最先進的代碼系統,可以表示所有語言。UTF-8是其中最流行的編碼格式,也是我們傳輸文件的首選。
(話說從這一期開始,“大貓的r語言課堂”有原文鏈接了,歡迎大家去戳哈。
什
么是ASCII、ANSI、UTF-8?
在過去的幾十年間,為了能夠在計算機中表示字符,人們發明了上百種編碼格式,標題中這些術語應該是最廣為人知的(可能還包括GB2312、GBK、GB18030)。說實話,這些編碼格式很多程序員自己也不是很清楚,我們自然也不需要刨根問題。但是這些編碼的特點、以及什么時候應該采用是大家最關心的問題。大貓試著用最淺顯易懂的語言按照時間順序對他們逐一介紹。
ASCII
大家把ASCII看作最原始的(當然還有更早的,但是我們沒有必要知道)編碼格式。ASCII最多只能表示128種字符(由整數0-127表示)。由于我們現在常用的字符數(別忘了emoji也是字符!)遠遠多于128,所以現在幾乎沒人用ASCII了。更重要的是,目前所有新的編碼全都兼容ASCII。
ANSI
由于ASCII的嚴重缺陷(法國人:法語是世界上最美的語言,你TM竟然計算機無法識別法文?!),人們試圖對ASCII進行擴展。這一擴展就不得了,每個國家都搞出了一套自己的編碼體系,而且互相不兼容!這還怎么玩!于是一群聰明人聚在一塊說:好吧,既然沒法統一用一套編碼體系,那么至少我們該給現有的編碼體系編個號吧?這樣我們以后交流數據,只要報上這個代號就知道對方用的是啥了。
于是一大群人聚集在國際標準組織位于維也納的總部進行了熱烈的討(撕)論(逼),之后,一大批編碼被納入了ISO體系(國際標準),這些編碼被統稱為ANSI編碼。對于R的使用者來說,我們只需要知道其中的一種編碼就夠了:ISO-8895-1(劃重點了!)ISO-8895-1又被稱為ISO-Latin-1或者Latin-1。這是一種能夠包含英語以及西歐絕大多數語言(法語德語西班牙語等)的編碼格式,后來幾乎成了“西方世界”的標準編碼格式。ISO-8895-1(Latin-1)也是R”欽定”的三種字符編碼格式之一,也即Encoding(char)所可能返回的三種結果之一。
那中文有沒有自己的ANSI編碼呢?當然是有的,按發明的時間順序,最常見的是中文編碼是GB2312,GBK,GB18030 (GB是“國標”的意思),越晚發明的編碼所包含的字符越多。然而他們在Windows系統中有不同的名稱(CP-936),關于中文編碼的請閱讀大貓上一期《我知道你不知道GB2312》。
每種語言都有自己的ANSI編碼,其中某個分支叫做ISO-8895-1 (Latin-1),被西方國家廣為采用,也是R所“欽定”的編碼之一;雖然ISO-8895-1 (Latin-1) 能支持很多西歐語言,但是仍舊無法處理中文!能夠處理中文的ANSI編碼中,最常見的有GB2312、GBK、GB18030;以上這些ANSI編碼在Windows中有另外的名稱,后述。
(注:ANSI是美國標準協會的簡稱,至于為啥它會成為某一類編碼的統稱又是另一個故事了。)
Unicode與UTF-8(UTF-16)
沒有幾個人能夠100%聲稱自己懂Unicode,因為Wikipedia上關于Unicode的定義都有很多矛盾的地方!但是沒關系,你知道下面大貓說的就夠了。
話說每種語言都有了自己的ANSI編碼系統,可謂皆大歡喜。但是每種語言都單獨編碼還是太麻煩了,有沒有可以用一套編碼體系涵蓋下所有的語言呢?結果自然是有的——Unicode。你看它的命名就知道了——“Uni”-code一出生就有一統天下的氣魄。但是Unicode有個致命的問題:它只是一種編碼的“思想”(確切來說叫 code point,嗯這個不重要……),而不是具體的編碼格式!這就好比我手上有地圖不等于我就能到達目的地,或是我知道核聚變的原理并不等于我能造的出氫彈一樣。于是維也納國際標準協會的那幫人又展開了一陣激烈的討(撕)論(逼),最后遵循Unicode的思想搞出了一套牛逼的編碼系統——UTF-8!
UTF-8的好處是顯而易見的:可以表示世界上任何一種字符,當然包括中文!數據采用UTF-8編碼可以在任何一個國家暢行無阻,再也不用擔心換了個國家SAS文件亂碼了。非常自然的,UTF-8成為了目前最受歡迎的編碼格式,Python 3就采用了UTF-8編碼。
也許很多小伙伴還看到過UTF-16以及UCS-2等編碼格式,這里一句話介紹下。UTF-16和UCS-2和UTF-8一樣,都是按照Unicode思想所開發出來的代碼。UTF-16的好處是它于在多語言環境中擁有比UTF-8更好的性能(因為它用16 bit來表示一個unit,因此不太需要把一個字符拆成多個byte。嗯這個你同樣不需要知道……)因此UTF-16成為了Windows以及Java內部所采用的編碼格式。至于UCS-2(或者UCS-4),雖然也是按照Unicode思想開發的,但是他們比UTF系列編碼更占空間,已經逐漸被淘汰了。
W
indows、Code page與R
當你處在壟斷地位的時候,很多事情就可以由著自己性子來了,例如蘋果的lighting接口。微軟也是一樣,剛說到在ANSI系統下,每種語言都有著自己符合ISO標準的編碼體系,微軟本來可以直接采用這套系統(注意當時Unicode還沒發明),但是微軟說:
這種獨有的Windows編碼體系被稱為Code page,中文翻譯為“代碼頁”。其實Code page是IBM的發明,只不過被微軟的Windows發揚光大了。關于ANSI標準與Windows標準的差異我們不做探討,小伙伴們同樣只要記住下面兩點的就行了:
一、剛才介紹的ANSI編碼中,能表示西歐大多數語言的那種叫做ISO-8895-1 (Latin-1),在Windows中他則被稱為Codepage-1252 (CP-1252)。CP-1252“幾乎”和Latin-1沒有區別。唯一重要的區別是:在英語環境,Windows平臺的R采用的是CP-1252而不是Latin-1編碼!例如大貓先把自己的操作系統區域設置為美國,然后運行Sys.getlocale()這個函數:
> Sys.getlocale()[1] “LC_COLLATE=English_United States.1252….
其中“English_United States.1252”說明現在R的區域是美國,語言是英語,采用的默認編碼格式是Windows的CP-1252。
二、剛才談到常見的中文ANSI編碼有:GB2312, GBK, GB18030,大家只要知道Windows中所采被稱為Codepage-936 (CP-936)就行了。具體而言,CP-936對應的是GBKs編碼,所以如果有一天有人告訴你他在Windows中選擇了CP-936的編碼格式,那么你就知道他實際上用的是GBK了。(當然現在的Windows在內部統一用Unicode表示字符,這個話題就太大了,不提)
在中文Windows環境中運行Sys.getlocale()會得到這個結果:
Sys.getlocale()
[1] “LC_COLLATE=Chinese (Simplified)_China.936..
其中“Chinese (Simplified)_China.936 ”說明現在R的區域是中國,語言是簡體中文,采用的編碼格式是Windows的CP-936。
總
結
ASCII是個古董,能表示的字符最少,且不能表示中文,幾乎被淘汰。后來所有新的編碼都兼容ASCII;ANSI是ASCII的擴展,由國際標準組織(ISO)定義,且每個語言都有一套自己的ANSI編碼體系,西文中最常用的那個版本叫 ISO-8895-1 (Latin-1),也是R所支持的三大編碼之一;簡體中文常見ANSI類型編碼有GB2312、GBK和GB18030;Windows把ISO標準的ANSI編碼稱為“代碼頁”(Code page,CP)其中ISO-8895-1 (Latin-1)在Windows中稱為CP-1252,簡中編碼GBK被稱為CP-936。Unicode是一類代碼的統稱,是出現最晚、最先進的代碼系統,可以表示所有語言。UTF-8是其中最流行的編碼格式,也是我們傳輸文件的首選。
下
期預告
這一期只是介紹了常見編碼,下一期大貓將在本期基礎上深入探索R的編碼系統~
