折
磨人的编码
“
编码问题就像蛀牙一样——平时不曾注意,直到他给你造成成吨伤害。
”
本期大猫将开个新帖介绍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系列编码更占空间,已经逐渐被淘汰了。
总结:UTF-8是按照Unicode思想所打造的、目前最流行的编码格式,支持中文,保存文件首选!其它的UTF系列编码仅在特定场合有用。
W
indows、Code page与R
当你处在垄断地位的时候,很多事情就可以由着自己性子来了,例如苹果的lighting接口。微软也是一样,刚说到在ANSI系统下,每种语言都有着自己符合ISO标准的编码体系,微软本来可以直接采用这套系统(注意当时Unicode还没发明),但是微软说:
“为了让Windows在世界上的任何角落都能发挥最佳的性能,我们采用了自己独有的编码体系。”
(这是我编的)
这种独有的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的编码系统~