Python中的编码与解码(转)
Python中的字符编码与解码困扰了我很久了,一直没有认真整理过,这次下静下心来整理了一下我对方面知识的理解。
文章中对有些知识没有做深入的探讨,一是我自己也没有去深入的了解,例如各种编码方案的实现方式等;二是我觉得只要提能对理解Python字符编码与解码的关键知识即可,想深入可以查其它资料。
文中的观点肯定有纰漏,只做参考,欢迎指正。
Unicode
参考:http://baike.baidu.com/view/40801.htm
Unicode是什么,这里不多说了,百科上面讲的很清楚了,这里只提下有助于理解本文主题的知识。
Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。每个字符都对应一个编号,编号的范围是0-0x10FFFF来。
字符编码方案
参考:http://baike.baidu.com/view/40801.htm
我们知道,每个Unicode字符对应一个编号,例如汉字“我”对应的编号是25105,但在程序中不是直接用编号来表示Unicode字符的(那得有多长的数字啊),而是表示成16进制格式,但具体怎么转换成16进制,不同的编码方案采用的方式不一样。
>>> s = u'我'
>>> ord(s)
25105
>>> s
u'\u6211'
>>> s.encode('utf-8')
'\xe6\x88\x91'
>>> s.encode('utf-16')
'\xff\xfe\x11b'
>>> s.encode('utf-32')
'\xff\xfe\x00\x00\x11b\x00\x00'
>>> s.encode('gbk')
'\xce\xd2'
>>>
我们用unicode()内置函数创建了一个Python中的unicode字符,然后ord()函数可以得到它在Unicode字符集中的编号。Python的unicode对象有一个encode()方法,用来对unicode对像进行编码。
这个示例中的一些知识,在后面会讲到,现在不用深究。这里提下UTF-8编码方式,其它的还没深入研究过,但不妨碍本文的主题。
UTF-8以字节为单位对Unicode编号进行编码。每个字节被转换成一个二位的十六进制数。UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。
Python支持很多的编码方案,包括ascii,utf-8,utf-16,utf32,gbk,gb2312等,完整的列表可以在下面的链接中找到:
http://docs.python.org/2/library/codecs.html#standard-encodings
Python中的字符串
在Python中,str 对象表示所有普通字符串对象,它只能表示ASCII码表中的字符,特点是每个字符占用一个字节,所以也叫做字节字符串(Byte string)。unicode 对象则可以表示所有Unicode字符集中的字符。
s = 'I love python'
u = u'我爱Python'
print isinstance(s, str)
print isinstance(u, unicode)
--输出
True
True
还可以使用 str() 函数 和 unicode() 从一个对象构建字符串,
str(object) 函数返回的结果通常可以通过定义 object 的 str 属性来定制返回的结果。
unicode()函数接受多个参数,与编码格式有关,这在后面会讲到。
Python中的Unicode 转义字符
我们常看到“ \u6211” 这样的字符,用json.dumps(obj)时,如里obj是unicode字符,包含非ASCII码,且ensure_ascii=True,那返回的结果字符串中就包含这种形式。这是个转义字符,表示Unicode字符“我”。但是注意的是,这种转义只在unicode字面量中有效,用print 输出时会自动转为对应的unicode字符。而在str字面量中没有特殊意义。web信息中常会遇到“\u4f60\u597d”类型的字符。首先’\u‘开头就基本表明是跟unicode编码相关的。python里str.decode()和str.encode()为我们提供了解码和编码的方法。其中str.decode('unicode_escape')能将此种字符串解码为unicode字符串。下面是在ubuntu的ipython中的操作,
>>> a = u'你好'
>>> a
u'\u4f60\u597d'
>>> print a
你好
>>> b = '你好'
>>> b
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> print b
你好
>>> c = '\u4f60\u597d'
>>>
>>> c
'\\u4f60\\u597d'
>>> print c
\u4f60\u597d
>>>
>>> d = r'\u4f60\u597d'
>>> d
'\\u4f60\\u597d'
>>> print d
\u4f60\u597d
>>> d == c
True
>>> e = c.decode('unicode_escape')
>>> e
u'\u4f60\u597d'
>>> print e
你好
>>>
其实6211是字符‘我’在Unicode字符集中的编号25105的16进制值
字符串字面量和程序中处理的字符串
在源代码中,字符串通常用字面量来表示
u = u'我爱Python'
但字面量是给人看的,程序看到的是对字面量进行处理后的字符,而且 str 字符串和 unicode 字符串的处理方式不一样。
unicode 字符串会将字面量中的非ASCII字符替换成Unicode转义符,但最后的结果是与原字符串等价的。
str类型的字面量会使用设置的编码格式进行编码处理,最后得到的是编码字符串(这点很重要,后面会提到)。编码字符串与原字符串不能等同。
--脚本
-- coding: utf-8 --
s = '我爱Python'
u = u'我爱Python'
print 'encoded str: ', repr(s)
print 'escaped unicode: ', repr(u)
print 'str: ', s
print 'decoded str: ', s.decode('utf-8')
print 'unicode: ', u
--输出
encoded str: '\xe6\x88\x91\xe7\x88\xb1Python'
escaped unicode: u'\u6211\u7231Python'
str: 鎴戠埍Python
decoded str: 我爱Python
unicode: 我爱Python
'\xe6\x88\x91\xe7\x88\xb1Python'是对 s 编码后的编码字符串,直接输出编码字符串会得到不一样的结果,因为实际上,'\xe6' 等被当作16进制转义字符来处理了。要想得到正确结果,需要先解码。
u'\u6211\u7231Python'是转义后的与 u 等价的unicode字符串
编码字符串
编码字符串,是指采用指定的编码格式对字符进行编码后得到的字符串。编码格式有很多中,例如 ascii、utf-8、gbk、gbk2312等。
编码字符串是纯 str 字符串,它表示原字符串的编码结果。直接输出编码字符串可能会与原来的字符串表示的值不一样,除非原来的字符串都是ASCII字符。
--脚本
-- coding: utf-8 --
s = '我'
s1 = '我爱Python'
print len(s)
print repr(s)
print s
print repr(s1)
print s1
--输出
3
'\xe6\x88\x91'
我
'\xe6\x88\x91\xe7\x88\xb1Python'
鎴戠埍Python
'\xe6\x88\x91' 和 '\xe6\x88\x91\xe7\x88\xb1Python' 就是编码字符串。在编码字符串中类似 '\xe6' 这种字符是Python中的16进制转义字符,被看作是一个字符,而不是4个字符。(Python转义序列:http://docs.python.org/2/reference/lexical_analysis.html#string-literals)
我们可以看到 s 的长度已经是3了,因为这里统计的是编码字符串的长度。
上面的例子有个小细节,字符串只包含单个字符的时候,print语句好像做了解码处理能直接输出正确的结果,但多个字符就会乱码。
这是为什么呢?
开始编码和解码
前面介绍了一些基本知识,现在开始来对字符串进行编码和解码了。
编码:
--脚本
-- coding: utf-8 --
u = u'我爱Python'
print 'encoded[utf-8]: ', repr(u.encode('utf-8'))
print 'encoded[gbk]: ', repr(u.encode('gbk'))
print 'encoded[ascii]: ', repr(u.encode('ascii'))
--输出
encoded[utf-8]: '\xe6\x88\x91\xe7\x88\xb1Python'
encoded[gbk]: '\xce\xd2\xb0\xaePython'
encoded[ascii]:
Traceback (most recent call last):
File "C:\Users\chw\Desktop\encoding.py", line 8, in
print 'encoded[ascii]: ', repr(u.encode('ascii'))
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
在上面的例子中,我们对一个unicode字符串采用了不同编码方式进行了编码,打印编码字符串。最后我们得到了一个错误,是因为ascii编码格式不能编码非ASCII字符。
对于str类型的字面量程序会自动做编码处理,所以就不要再去编一次码了。至于程序会采用何种编码格式要看设置,例如,在前面的脚本中,开头都有一个编码格式声明
-- coding: utf-8 --
这个声明告诉编译器该用什么编码格式处理str类型的字面量。在Python2.6以后的版本好像会根据保存源代码文件的格式来判断编码格式(没有声明的情况下),但先不深究了,总之开头指定编码格式应该是个好习惯。
解码:
str对象提供decode()方法来解码
--脚本
-- coding: utf-8 --
s = '我爱Python'
print repr(s)
print s
print s.decode('utf-8')
--输出
'\xe6\x88\x91\xe7\x88\xb1Python'
鎴戠埍Python #乱码了
我爱Python
前面我们讲过,str 字面量被自动编码成编码字符串,所以这里的 s 已经是编码后的编码字符串了,因此要输出 s 原来的字符,就需要解码。而开始我们指定了源文件的编码方式为utf-8,所以我们需要用utf-8格式来解码。
IDLE交互环境中的差异
在IDLE交互环境中,Unicode字面量好像不能正确的工作
>>> u = u'我爱Python'
>>> u
u'\xce\xd2\xb0\xaePython'
>>> isinstance(u, unicode)
True
>>> print u
ÎÒ°®Python
>>>
此例中,u实际上是表示'我爱Python'的编码字符串的unicode字符串,而不是'我爱Python'的unicode字符串了。也就是说,先将'我爱Python'编码成编码字符串,然后把编码字符串转换成unicode字符串。
在IDLE 交互环境中创建unicode对象的正确方式应该是下面这样:
>>> u = unicode('我爱Python', 'gbk')
>>> print repr(u)
u'\u6211\u7231Python'
>>> print u
我爱Python
unicode函数的第一个参数指定编码字符串,第二个参数指定这个编码字符串的编码格式。函数在处理中,先用第二个参数指定的编码格式解码第一个参数,根据不同的编码格式,可以直接返回一个unicode字符串。
如果省略第二个参数,unicode函数会将ascii作为默认编码格式(不管是交互环境还是脚本中都是这样)。
第二个参数的值与你的环境配置有关,我在windows下面使用IDLE交互环境,默认的编码是gbk或者是gbk兼容的编码格式。
在脚本中unicode字面量能被解析成正确的unicode字符串,没有IDLE那种令人费解的问题
---脚本
-- coding: utf-8 --
u = u'我爱Python'
print repr(u)
print 'unicode: ', u
---输出
u'\u6211\u7231Python'
unicode: 我爱Python
Python中的编码与解码(转)的更多相关文章
- python中的编码与解码
编码与解码 首先,明确一点,计算机中存储的信息都是二进制的 编码/解码本质上是一种映射(对应关系),比如‘a’用ascii编码则是65,计算机中存储的就是00110101,但是显示的时候不能显 ...
- python中的编码和解码
计算机中常见的编码方式有多种,英文一般是ascii编码,其他有unicode,utf-8,gbk,utf-16等编码. 常见编码方式: ASCII编码:ASCII是早期的编码,包含英文字母.数字和 ...
- Python中的编码和解码问题
关于Python中遇到的中文字符串的读取和输入时总是遇到一堆问题,到现在还不是特别明白,只是有了一个大概率的理解,就是:字符串是用什么编码格式编码的,就用什么编码格式来解码. encode()对字符串 ...
- python中base64编码与解码
在python3中用base64进行编码和解码的时候特别注意: 题目要求: 准备一张.jpg图片,比如:mm.jpg,读取图片数据并通过b85encode加密之后写入到新文件mm.txt文件中,然后读 ...
- Python 中 base64 编码与解码
base64 是经常使用的一种加密方式,在 Python 中有专门的库支持. 本文主要介绍在 Python2 和 Python3 中的使用区别: 在 Python2 环境: Python 2.7.16 ...
- python中的编码问题:以ascii和unicode为主线
1.unicode.gbk.gb2312.utf-8的关系 http://www.pythonclub.org/python-basic/encode-detail 这篇文章写的比较好,utf-8 ...
- 【转】【Python】 python中的编码问题报错 'ascii' codec can't decode 及 URL地址获取中文
1.unicode.gbk.gb2312.utf-8的关系 http://www.pythonclub.org/python-basic/encode-detail 这篇文章写的比较好,utf-8是u ...
- python基础系列教程——Python中的编码问题,中文乱码问题
python基础系列教程——Python中的编码问题,中文乱码问题 如果不声明编码,则中文会报错,即使是注释也会报错. # -*- coding: UTF-8 -*- 或者 #coding=utf-8 ...
- 转 python3中SQLLIT编码与解码之Unicode与bytes
#########sample########## sqlite3.OperationalError: Could not decode to UTF-8 column 'logtype' with ...
随机推荐
- java自带线程池和队列详细讲解<转>
Java线程池使用说明 一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后 ...
- Unix domain socket IPC
UNIX Domain socket 虽然网络socket也可用于同一台主机的进程间通讯(通过lo地址127.0.0.1),但是unix domain socket用于IPC更有效率:不需要经过网络协 ...
- PHP之PHP文件引用详解
HP的文件引用涉及到四个函数: 文件引用 1.include()2.include_once()3.require()4.require_once() 这四个函数常常会给PHP初学者造成困扰,总的来说 ...
- easyui_extension.js
$.extend($.fn.datagrid.methods,{ /** * 开打提示功能 * * @param {} * jq * @param {} * params 提示消息框的样式 * @re ...
- 一个线程可以拿到多个锁标记,一个对象最多只能将monitor给一个线程
当用Synchronized修饰某个方法的时候,表示该方法都对当前对象加锁. 给方法加Synchronized和用Synchronized修饰对象的效果是一致的. 一个线程可以拿到多个锁标记,一个对象 ...
- javascript实现打印功能
<input name="b_print" type="button" class="ipt" onClick="print ...
- 理解Loadrunner中的Browser Emulation Simulate
案例 测试环境描述: 客户端 5台 Windows2000机器.服务器端 20台机器 一台F5(负载均衡设备,提供一个唯一的IP供客户端访问) 客户端绑定Host后,使用域名http://www.* ...
- pythonanywhere笔记
https://www.pythonanywhere.com Deploying an existing Django project on PythonAnywhere Deploying a Dj ...
- 四个dos命令检查你的电脑是否中木马
一些基本的命令往往可以在保护网络安全上起到很大的作用,下面几条命令的作用就非常突出. 命令是再CMD中输入,不是运行框中 一.检测网络连接 如果你怀疑自己的计算机上被别人安装了木马,或者是中了病毒,但 ...
- word文档排版技巧
简介 市场部经常要出各种分析报告,一写就是洋洋洒洒几十页.文字功底深厚的小王写东西自然不在话下,然而每每困扰他的却是排版的问题,每次都要花大量的时间修改格式.制作目录和页眉页脚.最头疼的是上司看完报告 ...