欢迎加入python学习交流群 667279387

近期有同学在群里面问编解码的问题,为啥在python2中可以到了python3中为啥不行了。其实这设计到python2和python3编码的问题。这是一篇写比较不错的文档分享:Pragmatic Unicode ,这里在原文的基础上面进行了一下整理。

一、什么是编解码

1、什么是unicode

Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。

2、编码方式

字符集:为每一个字符分配一个唯一的 ID(码位 / 码点 / Code Point),编码规则:将码位转换为字节序列的规则(编码/解码 可以理解为 加密/解密 的过程)。为了将unicode字符转成bytes,需要进行编码,常见的编码方案有:UTF-16, UTF-32, UCS-2, UCS-4, UTF-8

二、python中的编解码

1、python2

1、str: 是比特序列

2、unicode: code points序列

>>> my_string = "Hello World"
>>> type(my_string)
<type 'str'> >>> my_unicode = u"Hi \u2119\u01b4\u2602\u210c\xf8\u1f24"
>>> type(my_unicode)
<type 'unicode'>

(1).encode() 和 .decode()

unicode .encode() → bytes //encode函数就是将unicode转换成bytes

bytes .decode() → unicode //对应的解码过程就是将bytes转成unicode

>>> my_unicode = u"Hi \u2119\u01b4\u2602\u210c\xf8\u1f24"
>>> len(my_unicode)
9 >>> my_utf8 = my_unicode.encode('utf-8')
>>> len(my_utf8)
19
>>> my_utf8
'Hi \xe2\x84\x99\xc6\xb4\xe2\x98\x82\xe2\x84\x8c\xc3\xb8\xe1\xbc\xa4' >>> my_utf8.decode('utf-8')
u'Hi \u2119\u01b4\u2602\u210c\xf8\u1f24'

更多请参考官方教程:https://docs.python.org/2/library/stdtypes.html?highlight=decode#str.decode

(2)编解码错误和处理

许多编码方案并能将全部的unicode字符进行编码。

>>> my_unicode.encode('ascii')
Traceback (most recent call last):
UnicodeEncodeError: 'ascii' codec can't encode characters in
position 3-8: ordinal not in range(128)

同样反过来,也并不是每一个str都是合法的unicode编码。

>>> my_utf8.decode("ascii")
Traceback (most recent call last):
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in
position 3: ordinal not in range(128) >>> "\x78\x9a\xbc\xde\xf0".decode("utf-8")
Traceback (most recent call last):
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x9a in
position 1: invalid start byte

这是官网给出来的一个在不能完全编码采用哪种方案进行处理的示例。

>>> unicode('\x80abc', errors='strict')
Traceback (most recent call last):
...
UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 0:
ordinal not in range(128)
>>> unicode('\x80abc', errors='replace')
u'\ufffdabc'
>>> unicode('\x80abc', errors='ignore')
u'abc'

(3)令人抓狂的隐式转换

下面就是python2中比较用起来爽,但是有时又让你很抓狂的东西—隐式转换。看下面这个例子:

>>> u"Hello " + "world"
u'Hello world' >>> u"Hello " + ("world".decode("ascii"))
u'Hello world' >>> sys.getdefaultencoding()
'ascii'

你可以将str和unicode进行拼接,语法解析器会自动给你做隐式转换。当然在很多时候是可以很好完成你的工作的,但是有时却不好使:

>>> u"Hello " + my_utf8
Traceback (most recent call last):
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in
position 3: ordinal not in range(128) >>> u"Hello " + (my_utf8.decode("ascii"))
Traceback (most recent call last):
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in
position 3: ordinal not in range(128)

2、python3

这里将python2和python3做了一个对比放在下面的表格里面了。

—— python2 python3
str a sequence of bytes a sequence of code points (unicode)
unicode a sequence of code points (unicode) ——
bytes —— a sequence of bytes

也就是说在python中,字符串为unicode格式的码位。下面看看在python3中的示例

>>> my_string = "Hi \u2119\u01b4\u2602\u210c\xf8\u1f24"
>>> type(my_string)
<class 'str'> >>> my_bytes = b"Hello World"
>>> type(my_bytes)
<class 'bytes'>

(1)encode和decode

在python3中,字符串str是unicode的,你可以利用encode函数将其转成其他的编码格式。

>>> nonlat = '字' //unicode格式
>>> nonlat
'字'
>>> print(nonlat)

>>> bytes(nonlat)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: string argument without an encoding >>> bytes(nonlat, 'utf-8')//和下面直接调用encode方法的区别可以参考下面给出的Stack Overflow的链接
b'\xe5\xad\x97' >>> nonlat.encode() //encode函数默认使用utf-8编码
b'\xe5\xad\x97' >>> nonlat.encode('utf-16')
b'\xff\xfeW[' >>> b'\xff\xfeW['.decode('utf-8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte >>> b'\xff\xfeW['.decode('utf-16')
'字'

区别:https://stackoverflow.com/questions/14472650/python-3-encode-decode-vs-bytes-str

更多请参考官方文档:https://docs.python.org/3/library/stdtypes.html?highlight=decode#bytes.decode

(2)无隐式转换

在python3中没有了python2中的隐式转换。你必须两种格式分开来处理。

>>> "Hello " + b"world"
Traceback (most recent call last):
TypeError: Can't convert 'bytes' object to str implicitly >>> "Hello" == b"Hello"
False >>> d = {"Hello": "world"}
>>> d[b"Hello"]
Traceback (most recent call last):
KeyError: b'Hello'

例如读取文件的时候,你就必须要注意格式的问题:

>>> open("hello.txt", "r").read()
'Hello, world!\n' >>> open("hello.txt", "rb").read()
b'Hello, world!\n' >>> open("hi_utf8.txt", "r").read()
'Hi \xe2\u201e\u2122\xc6\xb4\xe2\u02dc\u201a\xe2\u201e\u0152\xc3\xb8\xe1\xbc\xa4' >>> open("hi_utf8.txt", "r",
... encoding=locale.getpreferredencoding()).read()
'Hi \xe2\u201e\u2122\xc6\xb4\xe2\u02dc\u201a\xe2\u201e\u0152\xc3\xb8\xe1\xbc\xa4' >>> open("hi_utf8.txt", "r", encoding="utf-8").read()
'Hi \u2119\u01b4\u2602\u210c\xf8\u1f24' >>> open("hi_utf8.txt", "rb").read()
b'Hi \xe2\x84\x99\xc6\xb4\xe2\x98\x82\xe2\x84\x8c\xc3\xb8\xe1\xbc\xa4

(3)编程注意点

1、Unicode sandwich

Bytes on the outside, unicode on the inside Encode/decode at the edges



2、Know what you have

Bytes or Unicode? If bytes, what encoding?

>>> print type(my_unicode)
<type 'unicode'> >>> print repr(my_unicode)
u'Hi \u2119\u01b4\u2602\u210c\xf8\u1f24'

参考资料:

1、https://en.wikipedia.org/wiki/Unicode

2、https://docs.python.org/2/howto/unicode.html

3、https://stackoverflow.com/questions/14472650/python-3-encode-decode-vs-bytes-str

4、https://docs.python.org/3/library/stdtypes.html?highlight=decode#bytes.decode

欢迎加入python学习交流群 667279387

python2和python3编码问题的更多相关文章

  1. 字符编码、python2和python3编码的区别

    目录 字符编码 文本编辑器存储信息的过程 python解释器解释python代码的流程 python解释器与文本编辑器的异同 不同编码格式存入与读取数据的过程 乱码的分析 python2和python ...

  2. python2和python3编码

    python2编码 unicode:unicode 你好 u'\u4f60\u597d' | | | | encode('utf8')| |decode('utf8') encode('gbk')| ...

  3. Python2 和 Python3 编码问题

    基本存储单元 位(bit, b):二进制数中的一个数位,可以是0或者1,是计算机中数据的最小单位. 字节(Byte,B):计算机中数据的基本单位,每8位组成一个字节. 1B = 8b 各种信息在计算机 ...

  4. python2与python3编码

    #coding:utf8#一#1.在python2中,默认以ASCII编码chcp 936import sysprint sys.getdefaultencoding()# ascii#str:byt ...

  5. Python2和Python3编码的区别

    Python2 python2中有两种储存变量的形式,第一种:Unicode:第二种:按照coding头来的. 假设python2用utf8存储x='中文',当你print(x)的时候,终端接收gbk ...

  6. python2与python3编码问题

    python2: UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 33: 解决办法: 在报错的页面添加代码:  ...

  7. python2与python3编码(练习)

    #_author:来童星#date:2019/12/9import jsons='star'a=s.encode('utf8')print(s,type(s))# star <class 'st ...

  8. pickle 在python2 to python3 编码出现错误

    pickle.load(file) UnicodeDecodeError: 'ascii' codec can't decode byte 0xf5 in position 2: ordinal no ...

  9. Python全栈之路----Python2与Python3

    金角大王Alex  python 之路,致那些年,我们依然没搞明白的编码 python2与python3的区别 py2 str = bytes 为什么有bytes? 是因为要表示图片.视频等二进制格式 ...

随机推荐

  1. golang 服务诡异499、504网络故障排查

    事故经过 排查 总结 事故经过 11-01 12:00 中午午饭期间,手机突然收到业务网关非200异常报警,平时也会有一些少量499或者网络抖动问题触发报警,但是很快就会恢复(目前配置的报警阈值是5% ...

  2. 对学习Python自然语言处理的一点儿感悟

    研究生阶段,如果一开始找不到知识点,那就结合导师的研究课题以及这个课题设计到的知识领域,扎好基础知识能力.以我研究的自然语言处理领域为例,如果一开始不知道研究点,且又要安排学习计划,那么我会在选择: ...

  3. C#winfrom将XML数据保存读取删除

    //创建一个数据集,将其写入xml文件 string name = "1.xml"; System.Data.DataSet ds = new System.Data.DataSe ...

  4. 一.web服务机制

    web服务机制 我们先跟着**(Web服务器工作原理总体描述01)这张图,将一次Web服务的工作流程过一遍,我们假设以浏览器作为客户端(1) 用户做出了一个操作,可以是填写网址敲回车,可以是点击链接, ...

  5. PHP面向对象中new self( )和 new static( ) 的区别

    在PHP中 self指向定义了当前被调用方法的类, static指向调用当前静态方法的类. class A { public static $_a = 'Class A'; public static ...

  6. 01-MongoDB数据库基础

    一.MongoDB数据库基础 1.MongoDB数据库介绍 什么是MongoDB? MongoDB是非关系型数据库中的一种,是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统.在高负载的情 ...

  7. 深入理解跳表在Redis中的应用

    本文首发于:深入理解跳表在Redis中的应用微信公众号:后端技术指南针持续输出干货 欢迎关注 前面写了一篇关于跳表基本原理和特性的文章,本次继续介绍跳表的概率平衡和工程实现, 跳表在Redis.Lev ...

  8. selenium针对浏览器滚动条的操作

    我们在实际自动化测试过程中,肯定会遇到当前页面显示不到我们定位的元素.这就需要下拉滚动条才能显示出我们的元素: 而滚动条的按钮又是我们定位不到的,所以需要使用js脚本来完成: 1.先来说我们的下拉滚动 ...

  9. Java实现AES加密解密

    之前常用两种加密算法:Base64和Md5,前者容易破解,后者不可逆. AES采用对称加密方式,破解难度非常大,在可逆的基础上,能很好的保证数据的安全性. 这里介绍Java中实现AES加密算法的加密与 ...

  10. Flex带Checkbox的Tree

    想把Flex自带的Tree控件改成带有checkbox的样式. 原本以为同DataGrid一样,添加一个ItemRenderer就行,结果发现行不通. 进Tree控件的源码看了一下,发现Tree在自己 ...