一篇文章搞懂python2.7的编解码

本文深入探讨Python2.7中的编码概念,包括Unicode和UTF8。介绍了编码的原因,何时发生默认编码,如何修改编码规则,以及如何主动触发编码和解码。同时列举了常见的字符编码格式,如ASCII、ISO-8859-1、GB2312、GBK和UTF-8。

本文收录在我的博客:http://www.sskywatcher.com/blog/

 

目录

python中编码(encoding)是什么(what)

为什么需要编码(why)

python中什么时候发生默认编码(when)?

实例化str类的对象

隐式实例化str类的对象时会发生使用默认编码规则进行编码

文件IO对象的读取(使用open()方法):

修改默认编码规则的方法

修改python代码文件中出现的非ascii字符的默认编码

修改本次python会话中str()方法的默认编码规则

全局修改,使python解释器启动时,自动修改默认编码规则

python中怎么主动触发编码(how)?

unicode对象使用encode()方法

为什么要解码

PYTHON中什么时候发生解码

怎么主动发起解码

常见的字符编码格式有哪些?

读取自网络socket的编解码格式



python中编码(encoding)是什么(what)


python2.7中拥有两种字符串类,StrUnicode。python中的码点(code point)是一个int值, 一般表示为Base16的形式,值的范围为 0 到 0x10ffff。Unicode 描述了如何将单个字符表示为code points的规则。

一个Unicode字符串是code points的序列,. 这个序列在内存中需要被一个由bytes的集合来表示(一个byte的范围是 0–255)。 那么将一个Unicode字符串翻译成一个由bytes组成的序列的过程叫做encoding.

PS:

Base16编码使用16个ASCII可打印字符(数字0-9和字母A-F)对任意字节数据进行编码。Base16先获取输入字符串每个字节的二进制值(不足8比特在高位补0),然后将其串联进来,再按照4比特一组进行切分,将每组二进制数分别转换成十六进制,将对应的编码串接起来就是Base16编码。可以看到8比特数据按照4比特切分刚好是两组。

Base16编码后的数据量是原数据的两倍:1000比特数据需要250个字符(即 250*8=2000 比特)。换句话说:Base16使用两个ASCII字符去编码原数据中的一个字节数据。


为什么需要编码(why)

考虑一种简单的编码方式:直接用一些列32位的整数值来表示“python”这个字符串:

 

  P           y           t           h           o           n
0x50 00 00 00 79 00 00 00 74 00 00 00 68 00 00 00 6f 00 00 00 6e 00 00 00
   0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

以上表示法很直接,但是会有一系列问题

  1. 不可移植,不同的处理器可能使用不同的字节序;
  2. 使用原始码点非常浪费空间。 大多数文本中,主要的码点都小于127,亦或者小于255所以很大一部分的空间将被码点的内嵌0所占用。上述的字符串需要24个字节,而使用ASCII则只需要6个字节。虽然越来越大的内存可能让你不在乎这一点, 但是超量使用4倍的硬盘空间或者4倍的网络带宽就是不可忍受的了。
  3. 和一些已存在的C语言函数不兼容,比如 strlen()
  4. 许多网络协议是给予文本数据来定义的,它们通常不能处理包含内置0的字节。

所以,人们通常不会使用这种编码方式,取而代之的是,人们会根据自己的需要来选择一种合适而方便的编码方式,比如utf-8。


python中什么时候发生默认编码(when)?

实例化str类的对象

  • 内置方法str()

 str()方法会使用sys模块的默认编码方式对作为入参的字符串进行编码

 使用数字和英文字母,比较ascii编码后与编码前unicode实际异同:

>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> str_u=u"123abc"
>>> type(str_u)
<type 'unicode'>
>>> str(str_u)
'123abc'
>>> str1=str(str_u)
>>> type(str1)
<type 'str'>
>>> list(str_u)
[u'1', u'2', u'3', u'a', u'b', u'c']
>>> for c in list(str_u):
...     print(bin(ord(c)))
...
0b110001
0b110010
0b110011
0b1100001
0b1100010
0b1100011
>>>
>>> list(str1)
['1', '2', '3', 'a', 'b', 'c']
>>> for c in list(str1):
...    print(bin(ord(c)))
...
0b110001
0b110010
0b110011
0b1100001
0b1100010
0b1100011

使用中文做实验,可以发现使用ascii试图编码大于128的byte时python抛出了UnicodeEncodeError的错误。

>>> str_u1=u"中文"
>>> list(str_u1)
[u'\ufffd', u'\ufffd']
>>> for c in list(str_u1):
...     print(bin(ord(c)))
...
0b1111111111111101
0b1111111111111101
>>>
>>> len(str_u1)
2
>>> str2=str(str_u1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

 

式实例化str类的对象时会发生使用默认编码规则进行编码

  • 内置方法input()

 

  • 使用引号为变量直接赋值

ascii字符默认使用ascii进行编码;

非ascii字符则会使用系统变量的默认本地字符编码规则进行编码,下面的实验可以看出本地对非ascii使用了utf8编码。

>>> str3="中文"
>>> str3_u=u"中文"
>>> str4=str(str3)
>>> str5=str3_u.encode("utf8")
>>>
>>> str3==str4
True
>>> str4==str3_u
True
>>> type(str3_u)
<type 'unicode'>
>>> type(str3)
<type 'str'>
>>> type(str4)
<type 'str'>
>>>
>>> len(str3)
6
>>> len(str3_u)
2
>>> list(str3)
['\xef', '\xbf', '\xbd', '\xef', '\xbf', '\xbd']
>>> list (str4)
['\xef', '\xbf', '\xbd', '\xef', '\xbf', '\xbd']
>>> list(str3_u)
[u'\ufffd', u'\ufffd']
>>> list(str5)
['\xef', '\xbf', '\xbd', '\xef', '\xbf', '\xbd']

文件IO对象的读取(使用open()方法):

  • file.read()
  • file.readline()
  • file.readlines()

修改默认编码规则的方法

修改python代码文件中出现的非ascii字符的默认编码

python默认使用ascii编码去解释源文件,如果源文件中出现了非ASCII码字符,不在开头声明encoding会报错。



# encoding=utf8 #在代码开头加上该行指定本文件中非ascii字符的默认编码方式
print '中文'

修改本次python会话中str()方法的默认编码规则

>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> reload(sys)
<module 'sys' (built-in)>
>>> sys.setdefaultencoding("utf8")
>>> sys.getdefaultencoding()
'utf8'

全局修改,使python解释器启动时,自动修改默认编码规则

在Python安装的Lib\site-packages文件夹()windows下新建一个sitecustomize.py文件,内容为:

#coding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')

      重启Python解释器后可以发现编码已被设置为指定utf8。该操作的原理是系统在Python启动的时候,自行调用该文件,设置系统的默认编码。

需要注意的是linux与window不同系统对于python的lib路径均不一致,linux一般是放在以下路径:/usr/lib/python2.7/site-packages
 


python中怎么主动触发编码(how)?

unicode对象使用encode()方法

 


为什么要解码

 

 


PYTHON中什么时候发生解码

 

 


怎么主动发起解码

 

 


常见的字符编码格式有哪些?

  • ASCII 码
    ASCII 码总共有128个,用1个字节的低七位表示,0~31 是控制字符如换行、回车、删除等,32~126 是打印字符,可以通过键盘输入并且能够显示出来。
  • .ISO-8859-1
    128个字符显然是不够用的,于是ISO组织在ASCII 码基础上又制定了一系列标准来拓展 ASCII 编码,它们是ISO-8859-1 至 ISO-8859-15,其中 ISO-8859-1 涵盖了大多数西欧语言字符,所以应用的最广泛。ISO-8859-1 仍然是单字节编码,它总共能表示 256 个字符。
  • GB2312
    GB2312 的全称是 《信息技术 中文编码字符集》,它是双字节编码,总的编码范围是 A1~F7,其中A1 ~ A9 是符号区,总共包含682个字符; B0~F7 是汉字区,包含6763个汉字。
  • GBK
    全称是《汉字内码扩展规范》,它的出现是为了拓展 GB2312 ,并加入更多的汉字。它的编码是和GB2312 兼容的,也就是说用GB2312 编码的汉字可以用GBK 来解码,并且不会有乱码。
  • UTF-16
    说到UTF 必须提到 Unicode ,ISO 试图创建一个全新的超语言字典,世界上所有的语言都可以通过这个字典来相互翻译。UTF-16 具体定义了Unicode 在计算中的存取方法。UTF-16 用两个字节来表示 Unicode 的转化格式,采用定长的表示方法,即不论什么字符都可以用两个字节表示。
  • UTF-8
    UTF-16 存在存储空间浪费。UTF-8 采用了一种变长技术,每个编码区域有不同的字码长度。不同类型的字符可以由1~6 个字节组成。如果是一个字节,最高位为0,则表示这是 1 个 ASCII 字符,可见,所有ASCII 编码已经是UTF-8。

 


读取自网络socket的编解码格式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值