关于字符编码

最近玩因为工作关系被各种编码虐个半死,于是必须总结下,免得以后再才坑。

####unicode
unicode 又名国际码,万国码等,计算机领域业界标准。比如java和python3的内部的string都以unicode表示。

unicode 是一个符号集,仅仅规定了符号的二进制编码,并没有规定如何存储。目前常用的是2字节(16位)的Unicode 即UCS-2,理论上可以表示2^16=65536个字符。

但为了各国字符的扩展,unicode是分区的,也就是说,会划一块远大于他目前字符数量的区域给他用。比如,假设中文目前只有5k个字符,但给他留了1w个空间,这1w个空间就是中文字符区。

所以2个字节的地盘很快就被抢完了,所以就只能继续扩充长度了,一些小语种比如藏文,维语等还有无比蛋疼字符比如\u200b (zero width space character),他们都是三个字节的,最多可以表示2^24个字符。目前三个字节的地盘还没抢完。。。

####utf8
utf8其实是unicode的一种实现,其实是把unicode通过某种规则编码成utf8。

这么做有个好处,可以节省空间,unicode的话UCS-2标准的最小都要占用2个字节,而utf8是可变长的,可以使用1-4个字节表示一个符号

具体编码的详细过程可以参考这里

####汉字编码 GBK, GB2312, GB18030

那么既然unicode,utf-8收录了全世界的汉字,那么为什么还会有GBxxx,台湾有BIG5等各种各自国家专用的编码存在?

嗯,历史原因。

GB2312于1980年制定,然后由wiki发现,Unicode 1.0标准直到1991年10月才发布。于是在这段真空期内世界各地不可能不用计算机啊,既然用的话就肯定有输入本国字符的需要啊,但是由于ASCII的坑已经被占光,(就算不占其实也根本不够用)。于是各国自定的各种编码层出不穷,我国的话就是GBxxx系列了。

GB2312的编码规则:

  • 一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。

可是后来GB2312的字符已经不能满足需要,于是就有了GBK,它包含了GB2312的所有内容,并做了扩展(包括繁体字,符号等),方法是不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。

那个,其实GBK不是国家标准,而是微软标准。。。而GB18030才是国家标准。只不过因为从小用windows系统,所以。。。。

总的来说,GBK和他的子集GB2312都是2个字节表示一个汉字的。

这也是为什么GB系列字符经常被程序员的称呼为双字节字符集 (DBCS)

不过后来,随着电脑越来越普及,少数名族同胞也要用电脑了,这么多个民族,这么多种字符,于是乎现有的2字节标准已经不够用了,所以GB18030出现了。

GB18030的特点:

  • 共收录汉字70244个
  • 与 UTF-8 相同,采用多字节编码,每个字可以由1个、2个或4个字节组成。
  • 编码空间庞大,最多可定义161万个字符。
  • 支持中国国内少数民族的文字,不需要动用造字区。
  • 汉字收录范围包含繁体汉字以及日韩汉字。

GB系列的都有很好的兼容性,旧的系列都是新的系列的子集。

总结

我觉得,其实所谓的各种字符编码其实就是定义了一套规则,一套说明如何将其字符转换成ascii表示的过程和相应的逆过程。

最后举个例子应该就能明白。

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> unicode(u'我').encode('gb18030')
'\xce\xd2'
>>> unicode(u'我').encode('gbk')
'\xce\xd2'
>>> unicode(u'我').encode('utf8')
'\xe6\x88\x91'

>>> unicode(u'abc%^&*()').encode('gbk')
'abc%^&*()'
>>> unicode(u'abc%^&*()').encode('gb18030')
'abc%^&*()'
>>> unicode(u'abc%^&*()').encode('utf8')
'abc%^&*()'

因为abc%^&*()这些符号ascii已经有了,编码后保持不变,所以也就能兼容ascii了。

reference

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

http://www.crifan.com/files/doc/docbook/char_encoding/release/html/char_encoding.html#enc_unicode

http://www.phpweblog.net/fuyongjie/archive/2009/03/11/6374.aspx

avatar

lelouchcr's blog