欢迎加入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. 易初大数据 2019年11月2日 计算机英语 wangqingchao

    一.Match the explantions in Column B with words and expressions in Column A.(搭配每组中同意以的词或短语) 1.交换机(pos ...

  2. Spring源码解析之@Configuration

    @Configuration简介 用于标识一个类为配置类,与xml配置效果类似 用法简介 public class TestApplication { public static void main( ...

  3. 如何查看当前linux服务器是否支持虚拟化

    [root@localhost ~]# grep -E '(svm|vmx)' /proc/cpuinfo 或者: [root@localhost ~]# cat /proc/cpuinfo 找到fl ...

  4. Fuzzy模糊推导(Matlab实现)

    问题呈述 在模糊控制这门课程中,学到了与模糊数学及模糊推理相关的内容,但是并不太清楚我们在选择模糊规则时应该如何处理,是所有的规则都需要由人手工选择,还是仅需要选择其中的一部分就可以了.因此,在课程示 ...

  5. Head First设计模式——命令模式

    前言:命令模式我们平常可能会经常使用,如果我们不了解命令模式的结构和定义那么在使用的时候也不会将它对号入座. 举个例子:在winform开发的时候我们常常要用同一个界面来进行文件的下载,但是并不是所有 ...

  6. 一文带你深入了解 Redis 的持久化方式及其原理

    Redis 提供了两种持久化方式,一种是基于快照形式的 RDB,另一种是基于日志形式的 AOF,每种方式都有自己的优缺点,本文将介绍 Redis 这两种持久化方式,希望阅读本文后你对 Redis 的这 ...

  7. (二十六)golang--切片

    基本介绍: 切片是数组的引用: 切片的使用和数组类似: 切片的长度是可以变化的: 切片的定义 var a []int,注意和数组定义的区别: 切片不仅可以使用len函数,还有cap函数来计算切片的容量 ...

  8. hdu 2063 过山车 (二分图,最大匹配)

    过山车Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...

  9. PostgreSQL各数据类型的内置函数

    参考<PostgreSQL实战> 3.1.2 数字类型操作符和数学函数 PostgreSQL 支持数字类型操作符和丰富的数学函数 例如支持加.减.乘.除.模取取余操作符 SELECT 1+ ...

  10. vue项目引入自定义.css的样式文件

    ES6的引入方式: .vue文件中 css文件引入 <template></template> <style scoped> @import "../as ...