欢迎加入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. 从Gartner IT Symposium,看RPA“一半是海水一半是火焰”

    2019年,艺赛旗和Gartner建立了咨询合作,并在企业发展策略中汲取了Gartner的部分建议.今年Gartner在全球召开了多场IT Symposium,并在Symposium发布2020的相关 ...

  2. pxe批量部署

    功能: 批量全自动安装操作系统方法: dhcp 自动分配IP tftp 微系统 用来安装系统 httpd 网络源 操作流程: #检查环境 getenforce #检查selinux systemctl ...

  3. 201871010114-李岩松《面向对象程序设计(java)》第八周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  4. java多线程回顾1:线程的概念与创建

    1.进程与线程的概念 现在几乎所有操作系统都支持多任务,通常一个任务就是一个程序,一个运行中的程序就是一个进程.当一个程序行时,其内部也可能在执行多个任务,进程内每一个任务的执行流,就是一个线程. 所 ...

  5. Hybrid App: 看看第三方WebViewJavascriptBridge是如何来实现Native和JavaScript交互

    一.简介 在前面两篇文章中已经介绍了Native与JavaScript交互的几种方式,依次是JavaScriptCore框架.UI组件UIWebView.WebKit框架,这几种方式都是苹果公司提供的 ...

  6. Mybatis批量事务处理

    /** * 批量提交数据 * @param sqlSessionFactory * @param mybatisSQLId SQL语句在Mapper XML文件中的ID * @param commit ...

  7. Spring Boot Actuator监控使用详解

    在企业级应用中,学习了如何进行SpringBoot应用的功能开发,以及如何写单元测试.集成测试等还是不够的.在实际的软件开发中还需要:应用程序的监控和管理.SpringBoot的Actuator模块实 ...

  8. 宋宝华:Linux设备驱动框架里的设计模式之——模板方法(Template Method)

    本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 前言 <设计模式>这本经典 ...

  9. 用maven创建web项目(spring Mvc)

    用maven创建web项目(spring Mvc) 1.打开cmd进入到你要创建maven项目的目录下: 2.输入以下命令.然后根据提示输入相应的groupId.artifactId.version: ...

  10. linux与Windows进程控制

    进程管理控制 这里实现的是一个自定义timer用于统计子进程运行的时间.使用方式主要是 timer [-t seconds] command arguments 例如要统计ls的运行时间可以直接输入t ...