python编码和解码_Python中的编码与解码(转)

Python中的字符编码与解码困扰了我很久了,一直没有认真整理过,这次下静下心来整理了一下我对方面知识的理解。

文章中对有些知识没有做深入的探讨,一是我自己也没有去深入的了解,例如各种编码方案的实现方式等;二是我觉得只要提能对理解Python字符编码与解码的关键知识即可,想深入可以查其它资料。

文中的观点肯定有纰漏,只做参考,欢迎指正。

Unicode

Unicode是什么,这里不多说了,百科上面讲的很清楚了,这里只提下有助于理解本文主题的知识。

Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。每个字符都对应一个编号,编号的范围是0-0x10FFFF来。

字符编码方案

我们知道,每个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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/409926.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[html] 怎样使用iframe刷新父级页面

[html] 怎样使用iframe刷新父级页面 //在父页面中window.addEventListener("message",function(e){if(e.data.reload){winodw.location.reload()}}, false);//在子页面中window.parent.postMessage({reload:true})个人简介 我是歌谣,欢迎和大家一起交流前…

Nginx编译安装和平滑升级

一、Nginx的编译安装 1、安装依赖包gcc,gcc-c,pcre,openssl-devel 命令:yum -y install gcc gcc-c pcre-devel openssl-devel 2、下载Nginx源码包 Nginx下载地址:http://nginx.org/download/nginx-1.12.2.tar.gz …

python 调用shell 不阻塞_遇到问题---python调用shell脚本时subprocess.check_call不阻塞

遇到的问题使用命令subprocess.check_call(cmd, shellTrue, stdoutsubprocess.PIPE, stderrsubprocess.STDOUT)在ubuntu系统中python中使用subprocess.check_call调用shell命令。发现subprocess.check_call的阻塞无效,导致下面的命令缺失信息。但是同样的代码在cent…

android ListView详解

在android开发中ListView是比较常用的组件,它以列表的形式展示具体内容,并且能够根据数据的长度自适应显示。抽空把对ListView的使用做了整理,并写了个小例子,如下图。 列表的显示需要三个元素:1.ListVeiw …

[html] iframe在更改了src之后,不出现后退或者前进按钮怎么解决?

[html] iframe在更改了src之后,不出现后退或者前进按钮怎么解决? 更改src时可以先删除旧的iframe后,新建一个iframe设置好src添加进去个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。…

python一次性输入3个数_python实现输入数字的连续加减方法

不用库,写了很久,一直出bug,到网上一搜,可以直接输入之后,eval(str)即可得到结果! eval程序如下: sinput("请输入要运算的数字") print("The result is{}".format(eval(s))…

gd动态曲线 php_php中用GD绘制折线图

1 ClassChart{2 private $image; //定义图像3 private $title; //定义标题4 private $ydata; //定义Y轴数据5 private $xdata; //定义X轴数据6 private $seriesName; //定义每个系列数据的名称7 private $color; //定义条形图颜色8 private $bgcolor; //定义图片背景颜色9 priv…

Nginx网站用户认证

一、Nginx网站用户认证 用户认证:用户访问网页时需要输入一个用户名和密码才能打开网页。 nginx的默认网页时安装目录下的html/index.html,配置文件在安装目录下的conf目录中的nginx.conf 无用户认证网页 修改配置文件/usr/local/nginx/conf/nginx.conf(…

STL源码剖析学习二:空间配置器(allocator)

STL源码剖析学习二&#xff1a;空间配置器&#xff08;allocator&#xff09; 标准接口&#xff1a;vlaue_typepointerconst_pointerreferenceconst_referencesize_typedifference_typerebindallocator()--default constructorallocator(const allocator<U>&--copy c…

[html] iframe如何自动调整高度?

[html] iframe如何自动调整高度&#xff1f; 未跨域时&#xff0c;在iframe中利用他的父窗口对象将本页面的滚动高度设置给iframe的height 跨域时&#xff0c;在iframe中将自己的的滚动高设置在本页面内的一个隐藏于父页面不跨域的iframe的hash值&#xff0c; 在隐藏的iframe中…

python selenium 处理弹窗_python+selenium 抓取弹出对话框信息

抓取弹出对话框信息&#xff0c;困挠了我很久&#xff0c;我百度了很久&#xff0c;一直没有找到我想要的内容。最近学习到了。 有两种方法&#xff1a; 1、driver.switch_to.alert.text 2、result EC.alert_is_present()(driver).text 这个要导入from selenium.webdriver.sup…

Nginx基于域名的虚拟主机

一、基于域名的虚拟主机 修改配置文件/usr/local/nginx/conf/nginx.conf 创建新的虚拟主机的根目录和默认网页index.html 重新加载nginx的配置文件 查看两个虚拟主机 因为这两个域名是随便写的&#xff0c;所以需要修改windows系统的hosts文件&#xff0c;让电脑能够解析www.a.…

【100题】第三十四 实现一个队列

一&#xff0c;题目&#xff1a; 生产者消费者线程演示 一个生产者线程将int类型的数入列&#xff0c;一个消费者线程将int类型的数出列 二&#xff0c;分析&#xff1a; 这一个&#xff0c;为操作系统上的一个经典例子&#xff0c;以下是july给出的解答 …

[html] 如何禁止web端的页面缩放?

[html] 如何禁止web端的页面缩放&#xff1f; <meta name"viewport" content"widthdevice-width, initial-scale1,user-scalable0">个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家…

centos安装后两个启动项、_Windows安装Centos7双系统后Windows启动项消失

方法一&#xff1a;在Centos7下root登陆编辑 /boot/grub2/grub.cfgvim /boot/grub2/grub.cfg在第一行添加menuentry "Windows10" {insmod ntfsset root(hd0,)chainloader }其中(hd0, 1)的1代表你的windows10安装所在的盘修改完毕后保存并退出然后设置Windows10为默认…

如何给定两个gps坐标 算出航向角_机器人开发如何配置ROS中的TF变换关系?

当我们进行机器人开发时&#xff0c;常常需要面对TF坐标转换&#xff0c;本文以 Autolabor Pro1 与思岚激光雷达为例&#xff0c;介绍ROS TF的使用。Autolabor Pro1是什么&#xff1f;Autolabor Pro1是一款室内外通用机器人移动底盘。该平台上可集成激光雷达、摄像头、GPS等传感…

Tomcat架构与原理

Tomcat架构与原理 架构图 原理 ①、用户点击网页内容&#xff0c;请求被发送到本机端口8080&#xff0c;被在那里监听的Coyote HTTP/1.1 Connector获得。 ②、Connector把该请求交给它所在的Service的Engine来处理&#xff0c;并等待Engine的回应。 ③、Engine获得请求localhos…

[html] 微软雅黑是有版权的,在页面中使用font-family:Microsoft YaHei会不会有版权问题呢?

[html] 微软雅黑是有版权的&#xff0c;在页面中使用font-family:Microsoft YaHei会不会有版权问题呢&#xff1f; font-family: Microsoft YaHei的写法&#xff0c;个人、商用都不会有版权问题&#xff0c;可以放心使用&#xff01;但是如果是通过font-face引用微软雅黑的话&…

aodv路由协议分析

1 AODV 报文格式 AODV 有三种基本的协议报文类型&#xff1a;RREQ 报文、RREP 报文和RRER 报文。 1.1 RREQ 报文 a. 对RREQ 的处理 接收到RREQ 的结点做如下处理&#xff1a; &#xff08;1&#xff09;创建一个表项&#xff0c;先不分配有效序列号&#xff0c;用于记录反向路径…

rfid射频前端的主要组成部分有_第4章 RFID的射频前端(simple).ppt

(1)阅读器天线电路 * Microchip 公司的13.56 MHz应答器(无源射频卡)MCRF355和MCRF360芯片的天线电路 无源应答器的天线电路多采用并联谐振回路 * 并联谐振回路 在研究并联谐振回路时&#xff0c;采用恒流源(信号源内阻很大)分析比较方便。 并联谐振 谐振条件 - 实际中线圈的电…