主要介绍了python的编码机制,unicode, utf-8, utf-16, GBK, GB2312,ISO-8859-1 等编码之间的转换。

常见的编码转换分为以下几种情况:



自动识别 字符串编码



可以使用 chardet 模块自动识别 字符创编码

chardet 使用方法



unicode 转换为其它编码(GBK, GB2312等)



例如:a为unicode编码 要转为gb2312。a.encode('gb2312')

# -*- coding=gb2312 -*-
a = u"中文"
a_gb2312 = a.encode('gb2312') print a_gb2312



GBK 与 GB2312的区别



GB 码,全称是GB2312-80《信息交换用汉字编码字符集基本集》,1980年发布,是中文信息处理的国家标准,在大陆及海外使用简体中文的地区(如新加坡等)是强制使用的唯一中文编码。P- Windows3.2和苹果OS就是以GB2312为基本汉字编码, Windows 95/98则以GBK为基本汉字编码、但兼容支持GB2312。GB码共收录6763个简体汉字、682个符号,其中汉字部分:一级字3755,以拼音排序,二级字3008,以偏旁排序。该标准的制定和应用为规范、推动中文信息化进程起了很大作用。

GBK编码是中国大陆制订的、等同于UCS的新的中文编码扩展国家标准。GBK工作小组于1995年10月,同年12月完成GBK规范。该编码标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库。

GBK 包括 GB2312的所有编码,有些字GB2312没有,需要用GBK来编码。

转: gbk, gb2312,big5,unicode,utf-8,utf-16的区别



其它编码(utf-8,GBK)转换为unicode



例如:a为gb2312编码,要转为unicode. unicode(a, 'gb2312')或a.decode('gb2312')

# -*- coding=gb2312 -*-
a = u"中文"
a_gb2312 = a.encode('gb2312') print a_gb2312 a_unicode = a_gb2312.decode('gb2312') assert(a_unicode == a) a_utf_8 = a_unicode.encode('utf-8') print a_utf_8



非unicode编码之间的转换



编码1(GBK,GB2312) 转换为 编码2(utf-8,utf-16,ISO-8859-1)

可以先转为unicode再转为编码2

如gb2312转utf-8

# -*- coding=gb2312 -*-
a = u"中文"
a_gb2312 = a.encode('gb2312') print a_gb2312 a_unicode = a_gb2312.decode('gb2312') assert(a_unicode == a) a_utf_8 = a_unicode.encode('utf-8') print a_utf_8



判断字符串的编码



isinstance(s, str) 用来判断是否为一般字符串
isinstance(s, unicode) 用来判断是否为unicode
如果一个字符串已经是unicode了,再执行unicode转换有时会出错(并不都出错)

下面代码为将任意字符串转换为unicode

def u(s, encoding):
    if isinstance(s, unicode): return s else: return unicode(s, encoding)



unicode 与其它编码之间的区别



为什么不所有的文件都使用unicode,还要用GBK,utf-8等编码呢?

unicode可以称为抽象编码,也就是它只是一种内部表示,一般不能直接保存。
保存到磁盘上时,需要把它转换为对应的编码,如utf-8和utf-16。



其它方法



除上以上的编码方法,在读写文件时还可以使用codecs的open方法在读写时进行转换。



命令行默认编码检测和设置



可以用python自带的模块locale来检测命令行默认编码和设置命令行编码。

import locale
 
#get 
locale.getdefaultlocale() #('zh_CN', 'cp936') #set locale.setlocale(...)



汉字转Unicode编码



pd_name = pd_name.decode('utf-8')
    print pd_name nname = "" for c in pd_name: c = "%%u%04X" % ord(c); nname += c
http://www.pythonclub.org/python-basic/codec

===========================
知识点:
===========================
1. unicode是一个编码字符集, 即为每个字符设定了一个对应的编码表, 至于如何存储字符的编码, 并没有做规定.  
utf-8/utf-16等编码即是unicode的具体存储实现方式, 其中utf-8也是最常用的方式.
2. GB2312、GBK、 GB18030既是编码字符集, 也是存储方式. 
3. 如果py文件加了# -*- coding: utf-8 -*-, 字符串默认将以utf-8编码存储, 而且Eclipse也很智能将文件也按照UTF-8存放.
4. 如果py文件加了from __future__ import unicode_literals, 本py文件中声明的字符串将按照unicode 类型.  
5. 对于py程序从DB取出汉字的过程, 涉及到两个不同世界的存储方式, 一般都需要先做decode, 将其转为unicode.
6. 如果使用的是Oracle数据库, 汉字若存在varchar字段, 要看NLS_CHARACTERSET设定值, 比如ZHS16GBK, 需要做decode('GBK');  
如果汉字存在NVARCHAR中, 要看 NLS_NCHAR_CHARACTERSET 的设定, 因为NLS_NCHAR_CHARACTERSET多设定为UTF8, python程序就不需要做转换了. 



===========================
延伸阅读:
===========================
如joel所讲, 每个开发人员都应该清楚unicode和char set知识, 推荐阮一峰的文章:
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html 
http://www.pythonclub.org/python-basic/encode-detail

字体编辑用中日韩汉字Unicode编码表
http://www.chi2ko.com/tool/CJK.htm

SO上unicode_literals的问答
http://stackoverflow.com/questions/809796/any-gotchas-using-unicode-literals-in-python-2-6

http://www.cnblogs.com/harrychinese/p/UnicodeDecodeError_utf8_codec_decode_issue.html

编码的概念

编码就是将信息从一种格式转换成另一种格式,计算机只认识二进制,简单的理解,将我们眼睛看到的文字转换为计算机能够识别的二进制格式视为编码,而二进制以某种编码格式转换为我们能看的文字的过程可以看成是解码。既然计算机只能认识二进制0,1,那么我们用的字母、数字和文字等是怎样和他们对应的呢?那就请继续看吧!

 python中查看默认的编码规范是:



import sys print(sys.getdefaultencoding()) #运行结果: utf-8



 

ASCⅡ码

我们都知道计算机是米国发明的,起初的时候也只有米国那些国家使用,而他们的语言仅仅只有26个字母组成,再加上一些符号,所以在一开始的时候,用的编码规则就是ASCⅡ码。ASCⅡ,中文名叫美国信息交换标准代码,因为名叫American Standard Code for Information Interchange,下面我们来看看ASCⅡ表:

Python dict 转换编码 python编码转换在线_数据库

ASCⅡ码用一个字节,也就是8位二进制组来标识一个字符,比如00100001就代表字符!,第一版的ASCⅡ没有用到最高的一个bit,所以取值范围为0-127,只能表示128字符。为了满足西欧等国家的字符要求,于是用上了最高位的bit,能表示的字符也从128增加到了256个。

 

Python dict 转换编码 python编码转换在线_ico_02

在python中使用函数ord(),可以字符转换为对应数值,使用函数chr可以将数值转换为对应字符:



Python dict 转换编码 python编码转换在线_python_03



>>> ord("a") #将字符转换为数值 97 >>> ord("A") 65 >>> chr(65) 'A' >>> chr(97) #将数值转换为字符 'a' >>>



Python dict 转换编码 python编码转换在线_python_03



 

GB2312和GBK

当计算机漂洋过海来到了中国,ASCⅡ已经不能满足我大天朝的需求了,常用的汉字大致都有2k-3k。所以中国国家标准总局在1980发布了《信息交换用汉字编码字符集》,也就是GB2313标准。GB2312一共收录了7445个字符(6763个汉字和682个其他符号),包括拉丁字母、希腊字母和日文平假名等,基本上满足了国人的需求。

在GB2312中每个汉字使用两个字节来表示,分为高字节和低字节,汉字区高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768,其中有5个空位是D7FA-D7FE,规定第一个字节大于127的就代表这是一个汉字的开始(这一个字节和下一个字节就代表一个汉字),每个字节的最高位都位1。

但是对于人名、古汉语等方面出现的罕用字,GB2312不能处理,后来就出现了GBK。GBK向下兼容GB2312,其编码范围从8140到FEFE(不包括xx7F),共23940个码位,共收录了21003个汉字,这还是很厉害的了。现在我们使用的计算机默认的就是GBK编码。

Python dict 转换编码 python编码转换在线_ico_05

 

Unicode和UTF-8

我们国家搞出了GBK,其他的国家也搞出了各种各样的编码,比如小日本的SJIJ,宝岛台湾的BIG5,国际组织一看,这不行啊,每个地方都各自搞各自的,那么在不同的国家之间就会出现不兼容,我用GBK编码格式写的软件,弄到你编码格式为SJIJ的计算机就不能执行了。所以就出现了Unicode,也称万国码。unicode是用2个字节来表示一个字符的,65536类个字符,这足以覆盖世界上所有的文字。

这样虽好,但是美国人民就不开心了,我一个字母,比如'a'就需要占用一个字节,现在需要占用两个字节,这样就大大的浪费了内存和硬盘的空间,所有后来就出现了UTF-32,UTF-16和UTF-8,前两个这里就不在敖述了,现在并不常用,我们这看看这个UTF-8,UTF-8是一种可变长的编码格式,存储英文字母只需要一个字节,存储汉字需要3个字节,但超大字符集中的更大多数汉字要占4个字节。我们在内存里面的数据是unicode,在传输数据和保存数据的时候使用UTF-8已节省空间和带宽。

 

Python2的编码

在python2中默认的编码是ASCII,python2的字符串类型有两种:str和Unicode,这两个只是字符串类型的名字,我们主要看它们在内存里面的内存地址:



Python dict 转换编码 python编码转换在线_python_03



#coding=utf8

name = '彬彬'
name2 = u'彬彬'   #加u,将字符串类型改为Unicode
print  repr(name)
print  repr(name2)

#输出结果

'\xe5\xbd\xac\xe5\xbd\xac'   #字节数据
u'\u5f6c\u5f6c'              #Unicode数据



Python dict 转换编码 python编码转换在线_python_03


 

Python dict 转换编码 python编码转换在线_数据库_08

在python2中,str类型字符串类型在内存中存储的是bytes数据,Unicode类型字符串在内存中存储的是unicode数据。那两种数据之间是什么关系了?这里就涉及到了解码(encode)和编码(decode)了。



Python dict 转换编码 python编码转换在线_python_03



#coding=utf8

name = '彬彬'                #name为字节数据类型
name2 = u'彬彬'            #name为unicode数据类型
print  repr(name)         
print repr(name2)
name3 = name.decode('utf8')  
print type(name3)
print repr(name3)
name4 = name2.encode('utf8')
print type(name4)
print repr(name4)

#运行结果

'\xe5\xbd\xac\xe5\xbd\xac'
u'\u5f6c\u5f6c'
<type 'unicode'>
u'\u5f6c\u5f6c'
<type 'str'>
'\xe5\xbd\xac\xe5\xbd\xac'



Python dict 转换编码 python编码转换在线_python_03



由上运行结果可知,unicode转换为bytes数据的过程是编码。从bytes数据转换为unicode数据的过程是解码。我们再来看一下:



Python dict 转换编码 python编码转换在线_python_03



#coding=utf8 name = '彬彬' name3 = name.decode('big5') print name3 #运行结果 敶砍蓮



Python dict 转换编码 python编码转换在线_python_03



我们可以看到得到一堆乱文,name存在内存里的时候是以UTF编码成的bytes数据,而我们这里decode('big5')使用big5来解码,虽然成功了,但是输出结果却不是我们想要的结果。

当我们把第一行coding改为big5的时候就不会出现乱文了,



Python dict 转换编码 python编码转换在线_python_03



#coding=big5 name = '彬彬' name3 = name.decode('big5') print name3 #运行结果 彬彬



Python dict 转换编码 python编码转换在线_python_03



所以我们用什么规则编码的就要用什么区解码!

 

Python dict 转换编码 python编码转换在线_python_15

 注意:我们在终端显示出来的明文,就是你用户所看到的,其实都是已经转换成unicode到内存里面,而bytes数据一般都是计算机识别的。

 

Python3的编码

在Python3中也定义了2种类型的字符串类型,str和bytes,str类型存储unicode数据,bytes类型存储bytes数据。

Python dict 转换编码 python编码转换在线_开发工具_16



Python dict 转换编码 python编码转换在线_python_03



name = "彬彬" name2 = b"hello" print(type(name)) print(type(name.encode('utf8'))) print(type(name.encode('gbk'))) print(type(name2)) print(type(name2.decode('utf8'))) #运行结果 <class 'str'> <class 'bytes'> <class 'bytes'> <class 'bytes'> <class 'str'>



Python dict 转换编码 python编码转换在线_python_03



如上运行结果,bytes转换为unicode为解码,uicode转为bytes数据类型为编码。

Python dict 转换编码 python编码转换在线_python_19

 由上图所示,在不同的编码之间转换的时候,我们都要经过unicode这个中转站,没办法,虽然unicode老大哥强大呢,当我们想把utf-8编码的数据转换为gbk的,我们就需要把utf-8的数据先解码成unicode,再由unicode编码成gbk。

 在py2和py3中有个重要的区分就是,py2会自动把bytes数据解码成unicode,而py3就不会自动把bytes解码成unicode了。所以说py3更清晰的区分了bytes数据和unicode。



#py2中 print(u"liu" + "bin") #运行结果 liubin



Python dict 转换编码 python编码转换在线_python_03



#py3中 print("liu" + b"bin") #运行结果 Traceback (most recent call last): File "E:/py/字符编码2.py", line 2, in <module> print("liu" + b"bin") TypeError: Can't convert 'bytes' object to str implicitly



print("liu" + (b"bin").decode('utf8'))

#运行结果

  liubin



Python dict 转换编码 python编码转换在线_python_03



 

 

 一个.py文件的"一生"

 那我们创建.py文件,到执行.py文件,这里面的编码和解码是怎么来的呢?

1.当我们创建一个.py文件的时候,会有一个默认的编码格式(这里以pycharm为例),在右下角,默认是UTF-8,当然你也可以选择其他的编码:

Python dict 转换编码 python编码转换在线_Python dict 转换编码_22

2.当我们在.py文件里面写入代码的时候,会以unicode的编码格式保存在内存中;



print("你好,世界!")



 

3.当我们保存的时候,会将Unicode数据编码成utf-8格式的数据,然后保存在硬盘里面;

4.当我们执行文件的时候,pycharm会调用python的解释器来读取文件,在py2中,默认会以ASCII将代码解码成unicode数据,但是ASCII码并不认识中文,所以就会出现报错。



File "E:/py/�ַ�����.py", line 2 SyntaxError: Non-ASCII character '\xe4' in file E:/py/�ַ�����.py on line 2, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details



 

所以,在py2中,我们需要加上:



#coding=utf8 print("你好,世界!") #运行结果 你好,世界!



但是在py3中就不存在这个问题了,只要编码的时候适用的是UTF-8,python3默认的编码规范就是UTF-8,它会用UTF-8来将UTF-8的bytes数据解码成unicode,然后在计算机终端显示!