首页 > 代码库 > python - 字符编码篇

python - 字符编码篇

本章内容

  1. 什么是字符编码?
  2. python默认编码
  3. decode(解码)和encode(编码)

 

前言

  对于字符编码的问题,在学习python的过程中,很多新手都为之疯狂,本人也是其中之一,所以就来怼这个问题了。

一、什么是字符编码

  首先我们得知道,计算机中的所有数据,不管是文字、图片、视频、还是音频文件,本质上最终都是按照二进制存储的(就是一堆只有0、1的数字),并且计算机是只认识数字的,它并不认识你是 "A" 它是 "B" 。到这里需要先说一下,计算机的母语就是英语嘛,所以刚开始也就只是用的英语啦。我们还知道1 bytes = 8 bit ,也就是说一个字节等于8位,8位可以表达多少种不同的情况?每一位可以为0或1,那么8位则是2**8(2的8次方啊),也就是256种情况。然后呢计算机初期也只在美国使用,他们把数字、字母(包括大小写)、标点符号、空格这些基本要用的都加起来也只有127个,所以256完完全全够他们用了。于是他们用一个字节、用多种组合来存储英语的文字了。这样计算机认识这个数字的情况就相当于认识了这些字符,于是计算机就支持了英语这一门语言了。接下来进入正题:

  字符编码:(英语:Character encoding)也称字集码,是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。目的就是为了让计算机能 "认识" 字符。

  ASCII:上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。其实就是开头讲的东西,应该不难理解。ASCII码使用7位2进制数表示一个字符,7位2进制数可以表示出2的7次方个字符,共128个字符。

  随着计算机的大量使用,仅仅是英文字符已经不能满足各个国家的需求了,于是各国纷纷开始对ASCII码后面的编码进行抢占啊,哈哈。然后呢就出现了各种各样的编码。详细的编码发展历史见本节尾部。

  ANSI:一种字符代码,为使计算机支持更多语言,通常使用 0x00~0x7f 范围的1 个字节来表示 1 个英文字符,即ASCII编码(只用了7位)。超出此范围的使用0x80~0xFFFF来编码,即扩展的ASCII编码(用了8位)。在 ASCII 范围内它们应该是和 ASCII 一致的。Windows里的 ANSI 其实是Windows code pages,简体中文编码GBK,实际上它是 ANSI 的一个代码页 936 。

  注:128位到255的字符集对应拉丁文。一个字节就满了。

  GB2312:从上面我们知道了,计算机已经可以 "认识" 英文,但是不认识中文啊,而且一个字节也用完了,那怎么办?于是牛逼的中国人,重新写了一张表,把第8位对应的拉丁文全给删了,哈哈,然后规定一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时就表示一个汉字,于是6000多个汉字就硬生生给造出来了。前面的一个字节(高字节),从0xA1 用高 0xF7,后面一个字节(低字节),从0xA1到0xFE。GB2312其实就是对ASCII 的中文扩展。当然6000多个汉字是肯定不能满足中文需求的,所有后续又有GB18030和GBK,这个就自己去了解吧。

  UNICODE:由于各个国家都搞出了自己的编码标准,并且互相又不支持,所以这就造成了很多问题。于是国际标准化组织就搞出了个万国码--UNICODE。UNICODE规定用两个字节来表示一个字符,总共可以组合出65535种不同的字符,这已经足以解决我们编码与编码之间的支持问题了。

  UTF-8:UNICODE是支持UTF-8的,为什么要重新搞个UTF-8?因为UNICODE所有字符都是占2个字节,这样就使本来1个字节就能搞定的东西,非得用2个存储,这不是浪费内存吗?并且我们的程序中英文会远多余中文,所以位了节省内存,就搞出了UTF-8。UTF-8规定,英文只用一个字节,中文用3个字节。

  UTF-8版本虽然具有良好的国际兼容性,但中文需要比GBK/BIG5版本多占用50%的数据库存储空间,因此并非推荐使用,仅供对国际兼容性有特殊要求的用户使用。简单地说:对于中文较多的网站,适宜用GBK编码节省数据库空间。对于英文较多的网站,适宜用UTF-8节省数据库空间。

  以上就是基本的介绍了,详细发展历史--->>字符编码发展历史

 

二、Python默认的编码

  首先我们对操作系统的默认编码做下基本的了解。windows中文环境下cmd的默认编码是 GBK ,我们可以在cmd下输入chcp命令(如下图),返回结果:活动代码页:936(936代表的便是GBK);Linux下的terminal默认编码为 UTF-8

  在Python中,当源代码读取进行语法校验时,会将源代码中的字符串从声明的编码转换成 Unicode 类型,等到语法校验通过后,再将这些字符换回初始的编码。

技术分享

  • 在python 2.x 环境下

  python2.x 默认编码为ASCII ,可以通过以下方式可以检测:

1 import sys2 sys.getdefaultencoding()

  不过你不要天真的以为你指定编码为UTF-8就一定能输出中文了,在Windows下cmd窗口的字符编码是GBK,规定输出的字符集必须是GBK的,所以你传进去UTF-8的中文自然GBK是不兼容的,所以还是乱码。

  解决方法:

  1.

 1 # _*_ coding:utf-8 _*_ 2  3 # 定义一个变量内容为中文,字符集为UTF-8 4 temp = "中文" 5  6 # 解码,需要指定原来是什么编码 7 temp_unicode = temp.decode("utf-8") 8  9 # 编码,需要指定要转换成什么编码10 temp_gbk = temp_unicode.encode("gbk")11 12 # 输出转换成的gbk编码13 print(temp_gbk)

  2.

 1 # _*_ coding:utf-8 _*_ 2  3 # 定义一个变量内容为中文,字符集为UTF-8 4 temp = "中文" 5  6 # 解码,需要指定原来是什么编码 7 temp_unicode = temp.decode("utf-8") 8  9 # 输出转换成的gbk编码10 print(temp_unicode)11 # Windows终端需要GBK,DOS自动转换成GBK12 13 注:decode() 和 encode() 将在下一小节进行整理
  • 在python 3.x 环境下

  通过以上方法可以知道python3.x 默认编码为 UTF-8 。python 2.x 到 3.x 编码的问题有了很大的改进。2.x中编码的问题绝对会让你头疼,而3.x则轻松得多。虽然在 2.x 和 3.x 中都引入了Unicode,但是在 2.x 中的字符串有两种类型(unicode和str),默认是str类型,也就是说如果你要改变一个字符串的编码,你得先解码(decode)成unicode,然后再编码(encode)成你所要转的编码;而在 3.x 中默认就是unicode类型,例:字符串不再区分"abc"和u"abc", 字符串"abc"默认就是unicode。

  盗alex老师的一个图,下图只适用于python 2.x:

技术分享

  • 再说一下Unicode

  python之所以这么受欢迎,跟它引入了Unicode有莫大的关系,因为对不同国家和地区所用的字符的友好支持。

  现在我们来考虑一下,我们上面已经说了在python2.x 环境下,默认是ASCII,那么我们写代码时出现了ASCII不支持的字符,那怎么办?我们先看一个图:

技术分享

    (图片来源:http://nltk.googlecode.com/svn/trunk/doc/book/ch03.html)

  这个图我们可以看出来,所有超出ASCII范围的字符处理工作,无论是在输入之前,或者输出之后是什么编码格式,它们在python的执行内存中,都统一被解码(decode)成了Unicode格式。所以Unicode啊,这个万国码可不是闹着玩的,完全就是一个中转站,什么编码都能处理。

  注:在python2.x中可以看见 u‘abc‘ 这种前面加 u 的字符串,其实就是说它着是一个unicode类型的字符串,不过在 3  中这个方法被废弃了,因为不需要了。

三、decode() 和 encode()

  从上述两点中应该已经能知道这个东西了。

  decode(解码):清除原有编码格式,并解码成unicode。decode是将bytes类型变成str类型。所以,str类型是没有decode方法的。

    encode(编码):将unicode转成其他编码。encode是将str类型变成bytes类型。bytes类型也没有encode方法。

  在用这两个方法的时候经常会犯错,就是因为不清楚各个字符编码之间的兼容关系,以及运用对象。所以我们需要弄清楚兼容的问题,比如:UTF-8 和 GBK 都支持中文,但是就是不兼容,一个是从Unicode中提取出的扩展集,另一个则是在ASCII基础上进行重新修改的字符集。

  还有不清楚的看看以下两个例子:

技术分享
 1 #-*-coding:utf-8-*- 2 #指定编码格式 3  4 import sys 5 #导入模块 6  7 print(sys.getdefaultencoding()) 8 #打印默认编码 9 10 name = "里昂"11 name_gb2312 = name.decode("utf-8").encode("gb2312")12 #先解码成unicode(需指定原编码格式),再编码成gb231213 14 gb2312_to_gbk = name_gb2312.decode("gbk").encode("gbk")15 #先解码成unicode,同上,再编码成gbk16 17 print(name)18 #打印名字19 20 print(name_gb2312)21 #打印gb2312编码下的名字22 23 print(gb2312_to_gbk)24 #打印gbk编码下的名字
在python 2.x 中
技术分享
 1 import sys 2 #导入模块 3  4 print(sys.getdefaultencoding()) 5 #打印默认编码 6  7 name = "里昂" 8 #name_gb2312 = name.decode("utf-8").encode("gb2312")   py2 9 name_gb2312 = name.encode("gb2312")10  #py3 默认就是unicode,不用再decode11 12 gb2312_to_unicode = name_gb2312.decode("gb2312")13 #decode成unicode14 15 gb2312_to_utf8 = name_gb2312.decode("gb2312").encode("utf-8")16 #转成utf-817 18 print(name)19 #打印名字20 21 print(name_gb2312)22 #打印gb2312编码下的名字23 24 print(gb2312_to_unicode)25 #打印unicode编码下的名字26 27 print(gb2312_to_utf8)28 #打印utf-8编码下的名字
在python 3.x 中

 

 

  终于把这玩意搞完了,希望看到的朋友可以帮忙指出不足与错误的地方。感谢!

 

python - 字符编码篇