转摘地址:http://blog.segmentfault.com/stephenlee/1190000000489202
这几天用到一家公司的短信 API
,结果就遇到件囧事,因为编码格式不对,发过去的文字解析出了错误。于是就想到除了刚开始学习 web
的时候遇到过编码问题,似乎很久没有因为这个问题困扰过了,所以也就从没有仔细研究过,今天时间比较充裕,所以研究了下编码问题,特写博文一篇记录下心得体会。
起源 - ASCII
我们都知道在计算机内部,所有的数据在存储和运算的时候都应该使用二进制进行表示。例如字母,数字等等。通过二进制进行表示,我们可以指定很多规则来表示这些字符,为了避免不一致性,美国国家标准学会(American National Standard Institute , ANSI
)制定了 ASCII
(American Standard Code for Information Interchange
,美国信息交换标准代码)编码。
ASCII
码使用 7
位二进制数来表示 128
个字符,也就是用一个字节来表示,最前的一位默认为 0
。
我们都知道计算机是美国人发明的,接着美国人又制定了一套规则 ASCII
码用来在计算机中表示自己的语言和符号,由于英语的特殊性(26个字母搞定一切),所以一个字节的二进制就可以解决问题。
后来又有些符号和一些外来字母也需要表示,怎么办呢?我们前面讲到 ASCII
码刚开始制定时虽然用了一个字节的长度,但是空着最前的一位,所以只用了7位,还有一位没用起来,那么如果把这一位也用起来的话,也就是8位二进制,那么就可以表示256个字符了,于是扩展 ASCII
码诞生,保留原始的7位的基础上,使用了最前的一位。
发展 - GB2312
随着计算机的发展,越来越多的国家也使用上了计算机,那么也就需要计算机来展示自己国家的字符了,以中国为例,汉字的数量之多是英文字母无法想象的,区区一个字节是根本不可能装下庞大的汉字体系。所以我们中国自己制定了一套编码体系,称为 GB2312
(信息交换用汉字编码字符集),使用两个字节,也就是16位二进制,那么算下来最多就可以存下 65536 个字符了。最后收录了 6763 个汉字,覆盖了常用词的百分之90,所以基本是满足了计算机处理汉字的需求。为了兼容 ASCII
,大部分使用 GB2312
的程序都采用 EUC
存储方法。
这里虽然只介绍了 GB2312
,但是也隐含着一个问题,世界上这么多国家,每个国家都有不同的文化和语言,如果都制定属于自己的字符编码,那么就乱套了。
对计算机而言,当你通过设备输入字符时,它会根据你预置的编码规则来识别,如果两台电脑内的编码规则不一致,那么就无法识别彼此的符号信息了,对于以信息交流为目的的计算机体系而言,这无疑是个严重的问题。
统一 - Unicode
Unicode
又称为统一码或万国码,根据它的译名就能知道它的作用。它的出现就是为了解决字符编码的不一致性,虽然这期间也出现了不少很广泛使用的字符编码,但直到 Unicode
的出现才可以说真正出现了一套能容纳全球语言符号的编码规则。这里我们要注意,Unicode
仍然是支持 ASCII
的。
Unicode
虽然能容纳上百万数量的字符,但是它只是一个巨大的字符集,仅仅规定了每个符号的二进制代码,却没有制定细化的存储规则,例如当用三个字节存储一个字符时,它同时也可以被理解为存储了三个 ASCII
码,另外我们之前知道 ASCII
码只需要一个字节,但是如果 Unicode
规定每个字符使用三个字节来存储的话,那岂不是额外浪费两个字节的空间?所有这些未细化的问题都将导致 Unicode
的不一致性。
在 Unicode
出现之前,所有的字符集都是和具体编码方案绑定在一起的,都是直接将字符和最终字节流绑定死了,例如 ASCII
编码系统规定使用7位来编码 ASCII
字符集;GB2312
使用最多2个字节来编码所有字符,并且规定了字节序。这样的编码系统通常用简单的查表,也就是通过代码页就可以直接将字符映射为存储设备上的字节流了。
但这种方式的缺点在于,字符和字节流之间耦合得太紧密了,从而限定了字符集的扩展能力。因此 Unicode
在设计上考虑到了这一点,将字符集和字符编码方案分离开。每个字符在 Unicode
字符集中都能找到唯一确定的编号,但是决定最终字节流的却是具体的字符编码。
细化 - UTF-8
首先我们要明确 UTF-8(8-bit Unicode Transformation Format)
是在统一码(Unicode
)基础上细化并优化后的一种长度可变的字符编码方式,它是实现 Unicode
的方式之一,正如 @jysperm 所说,除了 UTF-8,
还有UTF-16,UTF-32
等都可以实现 Unicode
,但是 UTF-8
相对而言是用的最为广泛的。UTF-8
可以使用1到4个字节来,它通过自身的规则能够灵活地变化长度来存储 Unicode
字符。
总结
我们可以用记事本来测试不同字符编码的差异:
现在,我终于明白了部分关于编码的知识,不过博文中间可能有些概念理解得不是特别正确,如有错误,欢迎指正。
参考
http://www.joelonsoftware.com/articles/Unicode.html
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
《关于字符编码,你所需要知道的(ASCII,Unicode,Utf-8,GB2312…)》