python编码encode decode(解惑)

关于python 字符串编码一直没有搞清楚,今天总结了一下。

Python 字符串类型

Python有两种字符串类型:str 与 unicode。

字符串实例

# -*- coding: utf-8 -*-

# 这个是 str 的字符串
s = '关关雎鸠'

# 这个是 unicode 的字符串
u = u'关关雎鸠'

print isinstance(s, str)      # True
print isinstance(u, unicode)  # True

print s.__class__   # <type 'str'>
print u.__class__   # <type 'unicode'>

前面的申明表明,上面的 Python 源代码由 utf-8 编码,由于代码中有中文,所以需要加上。

# -*- coding: utf-8 -*- 

两种python字符串类型之间的转换

# 从 str 转换成 unicode
print s.decode('utf-8')   # 关关雎鸠

# 从 unicode 转换成 str
print u.encode('utf-8')   # 关关雎鸠

为什么从 unicode 转 str 是 encode,而反过来叫 decode?

因为 Python 认为 16 位的 unicode 才是字符的唯一内码,而大家常用的字符集如 gb2312,gb18030/gbk,utf-8,以及 ascii 都是字符的二进制(字节)编码形式。把字符从 unicode 转换成二进制编码,当然是要 encode。

反过来,在 Python 中出现的 str 都是用字符集编码的 ansi 字符串。Python 本身并不知道 str 的编码,需要由开发者指定正确的字符集 decode。

如果用错误的字符集来 encode/decode 会怎样?

# 用 ascii 编码含中文的 unicode 字符串
u.encode('ascii')  # 错误,因为中文无法用 ascii 字符集编码
                   # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)

# 用 gbk 编码含中文的 unicode 字符串
u.encode('gbk')  # 正确,因为 '关关雎鸠' 可以用中文 gbk 字符集表示
                 # '\xb9\xd8\xb9\xd8\xf6\xc2\xf0\xaf'
                 # 直接 print 上面的 str 会显示乱码,修改环境变量为 zh_CN.GBK 可以看到结果是对的

# 用 ascii 解码 utf-8 字符串
s.decode('ascii')  # 错误,中文 utf-8 字符无法用 ascii 解码
                   # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)

# 用 gbk 解码 utf-8 字符串
s.decode('gbk')  # 不出错,但是用 gbk 解码 utf-8 字符流的结果,显然只是乱码
                 # u'\u934f\u51b2\u53e7\u95c6\u5ea8\u7b2d'

陷阱

这要提到处理 Python 编码时容易遇到的陷阱。

字符串连接


# -*- coding: utf-8 -*-
# file: example2.py

# 这个是 str 的字符串
s = '关关雎鸠'

# 这个是 unicode 的字符串
u = u'关关雎鸠'

s + u  # 失败,UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)

在进行同时包含 str 与 unicode 的运算时,Python 一律都把 str 转换成 unicode 再运算,当然,运算结果也都是 unicode。

由于 Python 事先并不知道 str 的编码,它只能使用 sys.getdefaultencoding() 编码去 decode。sys.getdefaultencoding() 的值一般是 'ascii'。
显然,如果需要转换的 str 有中文,一定会出现错误。

% 运算的结果

# 正确,所有的字符串都是 str, 不需要 decode
"中文:%s" % s   # 中文:关关雎鸠

# 失败,相当于运行:"中文:%s".decode('ascii') % u
"中文:%s" % u  # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)

# 正确,所有字符串都是 unicode, 不需要 decode
u"中文:%s" % u   # 中文:关关雎鸠

# 失败,相当于运行:u"中文:%s" % s.decode('ascii')
u"中文:%s" % s  # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)

在 Python 3 已经取消了 str,让所有的字符串都是 unicode ——这也许是个正确的决定。

总结

string 模块已经停止了更新,只保留了 ASCII 码的支持,string 模块已经不推荐使用,在任何需要跟 Unicode 兼容的代码里都不要再用该模块,Python 保留该模块仅仅是为了向后兼容.

Python 把硬编码的字符串叫做字面上的字符串,默认所有字面上的字符串都用 ASCII 编码,可以通过在字符串前面加一 个'u'前缀的方式声明 Unicode 字符串,这个'u'前缀告诉 Python 后面的字符串要编码成 Unicode 字符串 .

内建的 str()函数和 chr()函数并没有升级成可以处理 Unicode.它们只能处理常规的 ASCII 编码字符串,如果一个 Unicode 字符串被作作为参数传给了 str()函数,它会首先被转换 成 ASCII 字符串然后在交给 str()函数.

如果该 Unicode 字符串中包含任何不被 ASCII 字符串支 持的字符,会导致 str()函数报异常.同样地,chr()函数只能以 0 到 255 作为参数工作.如果你 传给它一个超出此范围的值(比如说一个 Unicode 字符),它会报异常.

新的内建函数 unicode()和 unichar()可以看成 Unicode 版本的 str()和 chr().Unicode() 函数可以把任何 Python 的数据类型转换成一个 Unicode 字符串,如果是对象,并且该对象定义 了__unicode__()方法,它还可以把该对象转换成相应的 Unicode 字符串.

处理字符串的准则:

  • 程序中出现字符串时一定要加个前缀u.
  • 不要用str()函数,用unicode()代替.
  • 不要用过时的 string 模块 -- 如果传给它的是非 ASCII 字符,它会把一切搞砸。
  • 不到必须时不要在你的程序里面编解码 Unicod 字符.只在你要写入文件或数据库或者网络时,才调用 encode()函数;相应地,只在你需要把数据读回来的时候才调用 decode() 函数.

参考

http://in355hz.iteye.com/blog/1860787

《python核心编程 第二版》

猜你喜欢

转载自www.cnblogs.com/lanyangsh/p/10011758.html