Record and Summarize

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

一、字符编码

  在最初的时候,Internet上只有一种字符集——ANSI的ASCII字符集,它使用7 bits来表示一个字符,总共表示128个字符,其中包括了英文字母、数字、标点符号等常用字符。之后,又进行扩展,使用8 bits表示一个字符,可以表示256个字符,主要在原来的7 bits字符集的基础上加入了一些特殊符号例如制表符。

  后来,由于各国语言的加入,ASCII已经不能满足信息交流的需要,因此,为了能够表示其它国家的文字,各国在ASCII的基础上制定了自己的字符集,这些从ANSI标准派生的字符集被习惯的统称为ANSI字符集。这些派生字符集的特点是以ASCII 127 bits为基础,兼容ASCII 127。这样的字符集有很多,例如GB2312, BIG5, JIS 。

  由于每种语言都制定了自己的字符集,导致最后存在的各种字符集实在太多,在国际交流中要经常转换字符集非常不便。因此,提出了Unicode字符集。最初的Unicode使用16位,也就是2两个字节代表一个字符,这样一共可以表示65536个字符。显然,这样要表示各种语言中所有的字符是远远不够的。Unicode4.0规范考虑到了这种情况,定义了一组附加字符编码,附加字符编码采用2个16位来表示,这样最多可以定义1048576个附加字符,目前unicode4.0只定义了45960个附加字符。然而,目前最普及的还是2个字节表示一个字符的Unicode,在不引起混淆的情况下,下面所指的Unicode均是2字节表示一个字符。

  Unicode字符集有多种编码形式,例如UTF-8、16等,而ASCII字符集只有一种编码(即ASCII字符集本身),大多数ANSI字符集也只有一种编码,例如GB2312字符集的编码也是GB2312本身。注意,我们说的计算机的默认编码,例如linux的默认编码是utf-8,均指的是编码,而不是字符集。为什么Unicode字符集有多种编码,而不使用其本身作为字符编码?这可能是由于节省空间的目的,例如对于一个英文字符串,使用Unicode需要占用的空间是utf-8占用空间的2倍。下面介绍一下Unicode使用的各种字符编码:

  UTF-8的编码长度是可变的,并且是ASCII字符集的严格超集,也就是说ASCII中每个字符的编码在UTF-8中是完全一样的。UTF-8编码中,一个字符可能是1个字节,2个字节,3个字节或者4个字节长。一般来说,欧洲的字母字符长度为1到2个字节,而亚洲的大部分字符则是3个字节,附加字符(上文提到的在Unicode4.0中定义的附加字符)为4个字节长。Unix平台中普遍支持UTF-8编码,HTML和大多数浏览器也支持UTF-8编码,而window和java则支持UCS-2编码。UTF-8的主要优点:对于欧洲字母字符需要较少的存储空间;容易从ASCII字符集向UTF-8迁移。

  UCS-2是固定长度为16位的编码,每个字符都是2个字节。UCS-2只支持unicode3.0(unicode 3.0是使用2个字节表示一个字符),它对字符的编码形式与字符集中字符的编码是一一对应的;然而,当unicode 4.0中加入了另外2个字节的扩展字符编码后,UCS-2对这些额外的扩展编码就不再支持。UCS-2的优点:对于亚洲字符的存储空间需求比UTF-8少,因为每个字符都是2个字节;处理字符的速度比UTF-8更快,因为是固定长度编码的;对于windows和java的支持更好。

  UTF-16也是一种16位的编码。实际上,UTF-16就是UCS-2加上对附加字符的支持,也就是符合unicode4.0规范的UCS-2。所以UTF-16是UCS-2的严格超集。UTF-16中的字符,要么是2个字节,要么是4个字节表示的。UTF-16主要在windows2000以上版本使用。UTF-16相对UTF-8的优点,和UCS-2是一致的。

二、python字符串编码
  字符串在Python内部的表示是unicode,因此,在做编码转换时,需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。在python中输出一个汉字的unicode编码,可以看到这个汉字占了两个字节,如同上文中提到的,目前最普及的还是2个字节表示一个字符的Unicode

三、#encoding:utf-8(或gbk等)

  若源代码中包含非ascii字符,则必须在代码顶部引入;这行代码的功能是使python解释器能够顺利读取源代码,因为解释器默认会以ascii读取源代码,而ascii编码对非ascii字符不识别。但是要注意两点:在终端写实时python代码,不需要加这段代码,因为解释器就是以utf-8读入的。
  例如,#encoding:utf-8,那么,读入的源代码就是utf-8编码,那么所有的字符串也就都是以utf-8编码的(重要,最后还要提到)。

四、设置默认编码

  比如我有如下代码:

# encoding:utf-8
s = '中文' 
s.encode('gb18030') 

  由于# encoding:utf-8这句代码,因此字符串s就是utf-8编码;因为代码中没有解码的代码,所以Python会试图先将s解码为unicode,然后再编码成gb18030,但发现sys.defaultencoding是ascii;由于s是utf-8编码,因此用ascii解码显然是不对的,因此此处会报错。

  对于上述代码有两种修改方法:

  方法一:

# encoding:utf-8
s = '中文'
s.decode('utf-8').encode('gb18030')  # 加入用于解码的代码

  方法二:

# encoding:utf-8
import sys
reload(sys) #Python2.5初始化后会删除sys.setdefaultencoding这个方法,我们需要重新载入 
sys.setdefaultencoding('utf-8') #关于sys.setdefaultencoding,这个主要用在解码没有明确指明解码方式的时候使用。一般python的默认编码都是ascii,可以通过sys.getdefaultencoding获知。
s = '中文'
s.encode('gb18030')

五、字符串的进一步说明

  假如只考虑ascii和utf-8,如果一段代码能够成功执行,并且代码中含有中文字符串,那么所有字符串(无论是中文还是英文)必定都是utf-8编码。因为只有两种情况:终端实时执行的情况上面已经解释过;对于源代码文件的情况,如果没有这句代码“# encoding:utf-8”,则一定会报错,只要加入了“# encoding:utf-8”,那么所有字符串必定都是utf-8编码。
  而对于 u=u"汉字" 的解释:这种写法的意思是,把字符串解码为unicode,因此得到的是中间编码unicode;如果字符串是中文字符串,那么仅仅当字符串是utf-8编码时能够得到正确结果,如果不是(例如是gbk),那么得到的结果不正确,而且有可能报错。

六、unicode、str和repr函数

  unicode(object[encoding[errors]]),将一个对象转换为unicode字符串,如果object是一个字符串,那么encoding代表这个字符串的编码;如果object本身是一个unicode字符串,那么无需给出encoding

  str(object=''),将对象转换为字符串,它无法处理unicode字符串。

  repr(object),返回的字符串对象可以作为eval的参数。当object是非字符串对象,则它的返回值和str相同;当object是字符串对象,则repr会在该对象的外层再加上一层引号(此时,unicode字符串也被转换为了"u'\uxxxx'",即变成了一个普通ascii字符串,因此不会报错)。可以这么说,str的返回值更加具有可读性,而repr的返回值更加适合被开发者使用。

posted on 2013-12-30 17:46  zhangjing327  阅读(413)  评论(0编辑  收藏  举报