热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python2x的str/unicode转换以及python3x中的str/bytes转换

写在开头为什么哪里都会出现编码问题,而编码问题总是那么难搞懂?我想在读这篇博客前大家都应该深刻地了解下为什么会出现所谓的编码问题?Python2x中的strunicode转换字符的十

写在开头

为什么哪里都会出现编码问题,而编码问题总是那么难搞懂?我想在读这篇博客前大家都应该深刻地了解下为什么会出现所谓的编码问题?

Python2x中的str/unicode转换

字符的十六进制表达
首先,我们在ULtraEdit中做个试验
图一
图二
图三
图一:我们先用记事本保存了“中文”二字,然后以ANSI编码格式保存后用ULtraEdit打开,再转成十六进制编辑环境后就可以看到“中文”二字用ANSI编码存储的十六进制的表达,可以看到是4个字节。
图二:是用Unicode BigEndian保存的”中文“二字的十六进制表达,即从”4E“到”87“对应的4个字节,前面的两个字节是头,不管他,有兴趣的读者可以自行度娘。
图三:是用UTF-8编码存储的”中文“二字的十六进制表达,即从“E4“到”87“这6个字节,前三个字节是头,不管他。
可以看到,用不同的编码保存同样的字符,底层就会有不同的十六进制表达,ANSI底层是用两个字节存储一个中文字符的,Unicode也是用两个字节存储一个中文字符的,而UTF-8编码是用三个字节存储一个中文字符的。
Python2x中Str&Unicode
接下来我们来讨论Python2x中的Str和Unicode。
首先我打开Python2.7的编译环境。输入以下代码:

>>>a="中文"
>>>a
'\xd6\xd0\xce\xc4'
>>>type(a)
'str'>

>>>b=a.decode('gbk')
>>>b
u'\u4e2d\u6587'
>>>type(b)
'unicode'>

>>>a.decode('ascii')

可以看到在Python2.7shell中,我们输入”中文“这两个中文字符时,用了解释器的默认编码格式,在windows下即为GBK,所以我们看到的是上面第一个图中的十六进制表达。可以看到此时a的类型是str。
当我们对str类型的a用”gbk“解码后赋给变量b,可以b的类型是unicode,十六进制的表达式类似上面第二个图。
但是我们用ASCII编码去解码却得到DecodeError的结果。
所以我们得到一个结论:[str].decode(str对应的编码)=[unicode],并且用什么码编码就用什么码解码。

>>>c=b.encode('utf8')
>>>c
'\xe4\xb8\xad\xe6\x96\x87'
>>>type(c)
<type 'str'>
>>>print c
涓?枃

我们可以看到对unicode类型的变量b用utf8编码后变成了str类型的c,它的底层十六进制表达如上面的第三张图。unicode转换成utf8的规则可以参看这个网址上的博客:传送门
当我们print c的时候就打印出来乱码了,原因是此时的str变量c用的是utf8编码,但是解释器的编码是gbk,相当于用gbk的编码方式去解释用utf8编码的字符串,自然打印出来的是乱码。(而且,上面说过gbk是两个字节表示一个中文字符,utf8是三个字节表示一个中文字符,所以打印出来是三个乱码的字符)
所以我们得到另一个结论:[unicode].encode(你想要的编码方式)=[str],解释器编码方式要与字符串的编码方式一样才能解出正确的字符。

好了,说到这读者应该知道了Python里的str和unicode转换是怎么回事,以及底层那串”0101“的数字发生了什么变化。再说一句,Python2x中可以直接对str调用encode函数进行编码,我们可以这么理解他的背后实际做法:(str).decode(默认的编码).encode(你想要的编码)。那有读者要疑惑了,unicode decode是什么呢,Python2x中我试了下还是原unicode,我猜是Python不希望它出错,故意那这个接口留着,却不作为。

Python3x中的str/bytes转换

好吧,有些读者可能刚理解了上面说的Python2x中的unicode和str是怎么回事,不就是str解个码变成unicode,然后unicode编个码变成你想要的编码编的str嘛,简单!
然而到了Python3x后发现,咦,str不能解码了,str对象压根没有decode属性了,这还怎么入手?
首先我们要知道,在Python3x中不在有unicode这一说了,只有str和bytes这两个概念了(其实是Python把unicode隐藏了)。来看下面的代码

a = '中' 
a.decode('utf8') #AttributeError: 'str' object has no attribute 'decode'
print(type(a)) #<class 'str'>
print(a.encode('utf8')) #b'\xe4\xb8\xad'
print(type(a.encode('utf8'))) #<class 'bytes'>


b = bytes(a,"utf8")
print (b) #b'\xe4\xb8\xad'
print(type(b)) #<class 'bytes'>
print(b.decode('utf8')) #中
print(type(b.decode('utf8'))) #<class 'str'>

我们可以看到:
Python3x中(str).encode(编码)=(bytes)
(bytes).decode(‘bytes对应的编码’)=(str)
str不能上来就解码了
这是为什么呢?其实我们可以把unicode概念加上,帮助你理解,这里的str其实是unicode类型的字符串,你可以把它看成Python2x中的unicode,而bytes只不过带有指定编码的字节序列,可以看成Python2x中的str。这下你再看,是不是str(unicode)编码变bytes(str),bytes(str)解码变str(unicode)。可以这么想,我们输入的字符串直接被Python3x处理成Unicode形式的字符串,那么你可以干嘛,只能编码后才会变成字节序列啊。
说了这些可能你会觉得有点晕,那么来看下面的对比:
图一

图二

图一是Python3.4环境下的shell,图二是Python2.7环境下的shell,要读取的文本是以UTF-8的编码格式保存的,还是”中文“二字,我们可以想象,底层的字节序列应该是”\xe4\xb8\xad\xe6\x96\x87“。
可以看到Python2.7可以读取,并且底层的字节序列是怎么保存的他就怎么读取。但是Python3.4呢,他报错了,是decode错误,很显然,他在读取的时候想把UTF-8编码的字节序列用GBK去解码,想把它变成unicode,自然就出现了错误。我试了用ASNI编码保存的话,他就会正常读取,而且type是str。
所以我说实际上Python3x一旦读取了文本中的字符串,事实上它已经替你解码成unicode了,但是告诉你这是str类型。

总结

我们来总结一下,Python2x中,保存了什么字节序列,他就原封不动的读取进来,然后告诉你这是str类型(底层是字节序列),那么你可以把它decode一下,变成可以跨平台使用的unicode。好了,你要输出到文件中去了,那你得以一个具体的规则输出,也就是把unicode encode一下又变str(字节序列)。
Python3x中,文本中保存了字节序列,读取的时候Python解释器用设定的默认编码去解码了一道,变成了unicode,所以你不需要操作了,但是它告诉你这是str,你就当不知道,反正不管怎么夸平台都不会出错了。到了要输出的时候,再把unicode encode成bytes(字节序列)。


推荐阅读
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文介绍了在处理不规则数据时如何使用Python自动提取文本中的时间日期,包括使用dateutil.parser模块统一日期字符串格式和使用datefinder模块提取日期。同时,还介绍了一段使用正则表达式的代码,可以支持中文日期和一些特殊的时间识别,例如'2012年12月12日'、'3小时前'、'在2012/12/13哈哈'等。 ... [详细]
  • Python 可视化 | Seaborn5 分钟入门 (六)——heatmap 热力图
    微信公众号:「Python读财」如有问题或建议,请公众号留言Seaborn是基于matplotlib的Python可视化库。它提供了一个高级界面来绘制有吸引力的统计图形。Seabo ... [详细]
  • 像c语言中的goto,shell中的break后面跟跳出层次的在方法在python中都没有,这可不是因为python设计的low,而是允许一次性跳出多个循环很容易造成程序流程的混乱 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 合并列值-合并为一列问题需求:createtabletab(Aint,Bint,Cint)inserttabselect1,2,3unionallsel ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • 十大经典排序算法动图演示+Python实现
    本文介绍了十大经典排序算法的原理、演示和Python实现。排序算法分为内部排序和外部排序,常见的内部排序算法有插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。文章还解释了时间复杂度和稳定性的概念,并提供了相关的名词解释。 ... [详细]
  • 超级简单加解密工具的方案和功能
    本文介绍了一个超级简单的加解密工具的方案和功能。该工具可以读取文件头,并根据特定长度进行加密,加密后将加密部分写入源文件。同时,该工具也支持解密操作。加密和解密过程是可逆的。本文还提到了一些相关的功能和使用方法,并给出了Python代码示例。 ... [详细]
  • 本文分析了Wince程序内存和存储内存的分布及作用。Wince内存包括系统内存、对象存储和程序内存,其中系统内存占用了一部分SDRAM,而剩下的30M为程序内存和存储内存。对象存储是嵌入式wince操作系统中的一个新概念,常用于消费电子设备中。此外,文章还介绍了主电源和后备电池在操作系统中的作用。 ... [详细]
  • 本文详细介绍了使用C#实现Word模版打印的方案。包括添加COM引用、新建Word操作类、开启Word进程、加载模版文件等步骤。通过该方案可以实现C#对Word文档的打印功能。 ... [详细]
  • 我从来没有学过c语言,学不会C语言
    本文目录一览:1、我从没学过计算机C语言,怎么准备考二级C? ... [详细]
  • 这篇文章给大家分享的是有关python3怎样中文转换编码的内容。小编觉得挺实用的,因此分享给大家做个参考。一起跟随小编过来看看吧。示例:处理 ... [详细]
  • 浅谈Python3中打开文件的方式(With open)
    浅谈Python3中打开文件的方式(With open)-目录0.背景知识1.常规方式:读取文件-----open()2.推荐方式:读取文件-----WithOpen1).读取方式 ... [详细]
author-avatar
飞鱼
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有