您的位置:首页 > 编程语言 > Python开发

python学习之unicode编码

2016-06-30 15:26 519 查看
python内建的字符串有两种类型:
str
Unicode
,它们拥有共同的祖先basestring。

Unicode也称做万国码,它为每种语言设定了唯一的二进制编码表示方式,提供从数字代码到不同语言字符集之间的映射,从而可以满足跨平台、夸语言之间的文本处理要求。

Unicode编码系统可以分为编码方式和实现方式两个层面。
在编码方式上,分为UCS-2和UCS-4两种方式,UCS-2用两个字节编码,UCS-4用4个字节编码。
一个字符的Unicode编码是确定的,但是在实际传输过程中,由于系统平台的不同以及处于节省空间的目的,实现方式有所差异。Unicode的实现方式称为Unicode转换格式,简称为UTF,包括UTF-7、UTF-16、UTF-32、UTF-8等,较为常见的是UTF-8,他的特点是对不同范围的字符使用不同长度的编码,其中0x00 ~ 0x7F的字符的UTF-8编码与ASCII编码完全相同,UTF-8编码的最大长度是4个字节。


str与字节码

s = "中国北京"


s是个字符串,它本身存储的就是字节码。那么这个字节码是什么格式的?

如果这段代码是在解释器上输入的,那么这个s的格式就是解释器的编码格式,对于windows的cmd而言,就是gbk。

如果将段代码是保存后才执行的,比如存储为utf-8,那么在解释器载入这段程序的时候,就会将s初始化为utf-8编码。


unicode与str

python 在内部使用两个字节来存储一个unicode,使用unicode对象而不是str,好处就是unicode方便于跨平台。

你可以用如下两种方式定义一个unicode:
s1 = u"中国北京"

s2 = unicode("中国北京", "utf-8")



encode与decode

decode()
方法讲其他编码对应的字符串解码为Unicode,
encode()
方法将Unicode编码转换为另一种编码。

我们可以写这样的代码:
# -*- coding: utf-8 -*-

# su是一个utf-8格式的字节串

su = "中国北京"

# s被解码为unicode对象,赋给u

u  = s.decode("utf-8")

# u被编码为gbk格式的字节串,赋给sg

sg = u.encode("gbk")

print sg


看下面这个例子:
s = "中国北京"

s.encode('gbk')


上面的代码会报错,错误信息:
UnicodeDecodeError:
'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)


原因:当对str进行编码时,会先用默认编码将自己解码为unicode,然后在将unicode编码为你指定编码,而python的默认编码defaultencoding是ascii码,所以会出错。

上面代码等价于:
s = "中国北京"

# sys.getdefaultencoding() == "ascii"

s.decode(sys.getdefaultencoding()).encode('gbk')


解决方法如下:
# 重新设置默认编码

reload(sys)

sys.setdefaultencoding('utf-8')

s = "中国北京"

s.encode('gbk')


再比如你使用str创建unicode对象时,如果不说明这个str的编码格式,那么程序也会使用defaultencoding。
# 两者等价

u = unicode("中国北京")

u = unicode("中国北京", sys.getdefaultencoding())


默认的defaultcoding:ascii是许多错误的原因,所以早早的设置defaultencoding是一个好习惯。

普通字符和Unicode进行字符串连接的时候抛出
UnicodeDecodeError
异常。
s = "中文北京" + u"Chinese Test"

print s


原因:使用 + 操作符来进行字符串的连接时,左边为中文字符串,类型为str,右边为Unicode字符串,当两种类型的字符串连接的时候,python将左边的中文字符串转换为Unicode再与右边的Unicode字符串连接,将str转换为Unicode时使用系统默认的ASCII编码对字符串进行编码,就会出现
UnicodeDecodeError
异常。

解决方法:
指定str转换为Unicode时的编码方式。
s = "中文北京".decode('utf-8') + u"Chinese Test"


将Unicode字符串进行UTF-8编码
s = "中文北京" + u"Chinese Test".encode("utf-8")



文件头声明编码

一般来说进行源文件编码声明有三种方式:
#coding=utf-8


# 大多推荐使用此方式

#!/usr/bin/python

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


#!/usr/bin/python

# vim: set fileencoding=utf-8:


文件头声明编码的作用:
如果代码中有中文注释,就需要此声明。
比较高级的编辑器(比如我的emacs),会根据头部声明,将此作为代码文件的格式。
程序会通过头部声明,解码初始化 
u"中国北京"
这样的unicode对象,(所以头部声明和代码的存储格式要一致)。


几点建议

基本设置
主动设置defaultencoding(默认的是ascii)
代码文件的保存格式要与文件头部的# -*- coding:xxx -*- 一致
如果是中文,程序内部尽量使用unicode,而不用str

关于打印

你在打印str的时候,实际就是直接将字节流发送给shell。如果你的字节流编码格式与shell的编码格式不相同,就会乱码。

而你在打印unicode的时候,系统自动将其编码为shell的编码格式,是不会出现乱码的。

程序内外要统一

如果说程序内部要保证只用unicode,那么在从外部读如字节流的时候,一定要将这些字节流转化为unicode,在后面的代码中去处理unicode,而不是str。
with open("test.txt") as f:

for i in f:

# 将读入的utf-8字节流进行解码

u = i.decode('utf-8')

....


如果把连接程序内外的这段数据流比喻成通道的的话,那么与其将通道开为字节流,读入后进行解码,不如直接将通道开为unicode的。
# 使用codecs直接开unicode通道

file = codecs.open("test.txt", "r", "utf-8")

for i in file:

print type(i)

# i的类型是unicode的


所以python处理中文编码问题的关键是你要清晰的明白,自己在干什么,打算读入什么格式的编码,声明的的这些字节是什么格式的,str到unicode是如何转换的,str的一种编码到另一种编码又是如何进行的。 还有,你不能把问题变得混乱,要自己主动去维护一种统一。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: