项目github地址:bitcarmanlee easy-algorithm-interview-and-practice
欢迎大家star,留言,一起学习进步

1.前言

虽然用python有一些年头了,但是在处理中文字符串的时候还是经常会遇到UnicodeEncodeError,UnicodeDecodeError等问题。每次都是随便调一调,程序能正常run以后就不管了。不巧今天又遇到了同样的状况,于是痛下决心,一定要把python中的字符编码问题搞清楚。

2.字节与字符

计算机存储的任何数据,包括各种文本、图片、音视频文件等等,实际上都是一串二进制数字01字节序列组成的。相信大家都知道,一个字节Byte(B)是8个比特bit(b)。
而字符,自然就是符号了。比如说二十六个英文字母,阿拉伯数字,以及在python中最坑爹的汉字都是字符。python中遇到的字符编码问题,大部分都与汉字有关系。
写过java的小伙伴都知道,java中的IO模块,从大的方向来说,就可以分为字节流与字符流。字节流包括InputStream与OutputStream,字符流包括Writer与Reader。
有的同学会有疑问,为什么要搞这么复杂?统一用字节或者字符不就行了?
字节一般用来存储与网络传输,这样可以节省存储空间与网络传输带宽。而字符主要是用于显示,方便大家阅读。试想你正在debug,结果所有的输出是一堆01011100这种,那你还不得疯了。

3.编码(encoding)与解码(decoding)

字符编码(Character encoding)、字集码是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII。其中,ASCII将字母、数字和其它符号编号,并用7比特的二进制来表示这个整数。通常会额外使用一个扩充的比特,以便于以1个字节的方式存储。(参考文献1)
encoding是将字符转换为字节,那么反过来将字节转换为字符则是decoding,两者是可逆的。编码主要是为了存储传输,而解码是为了方便阅读。

4.utf-8与unicode区别

在正式讲python字符编码问题之前,还需要先扯清除unicode跟utf-8的关系。
简单来说,unicode是一个字符集,而utf-8是一个编码规则,两者并不是同一维度的东西。
字符集:为每一个字符分配一个唯一的 ID(学名为码位 / 码点 / Code Point)
编码规则:将码位转换为字节序列的规则(编码/解码 可以理解为 加密/解密 的过程)

4.python 2.7中的字符串

python2x中的字符串实际有两种类型: str与unicode。很多时候出现的各种问题,就是出现在这上面。
下面我们在python解释器中简单测试一下

>>> s = "你好"
>>> s
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> type(s)
<type 'str'>

上面的代码可以看出,s是str类型,在内部的存储方式就是一堆01二进制字节序列,显示出来是一串十六进制字符。
很多时候我们看到定义字符串的时候会在前面加上一个前缀u,这个u其实就是表示这个字符串是unicode形式:

>>> s = u"你好"
>>> s
u'\u4f60\u597d'
>>> type(s)
<type 'unicode'>

我们看看编码的过程,大家记住编码是从字符->字节

>>> s = u"你好"
>>> s
u'\u4f60\u597d'
>>> type(s)
<type 'unicode'>
>>> s.encode('utf-8')
'\xe4\xbd\xa0\xe5\xa5\xbd'

再看看解码过程,解码自然就是从字节-> 字符

>>> s = "你好"
>>> s
'\xe4\xbd\xa0\xe5\xa5\xbd'
>>> type(s)
<type 'str'>
>>> s.decode("utf-8")
u'\u4f60\u597d'

5.UnicodeEncodeError

既然是UnicodeEncodeError,那么应该是在字符->字节的环节出现了问题。来看下面的例子。

def t1():f = open("ttt", "w")u1 = u'你好'f.writelines(u1 + "\n")t1()

运行这段代码以后,会有如下问题:

TypeError: writelines() argument must be a sequence of strings

这个问题比较好解释,writelines方法需要的是一个字符串序列,而u1是个unicode。
将代码稍作修改

def t1():f = open("ttt", "w")u1 = u'你好'f.write(u1)t1()
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

调用write方法时,如果传入的是字符串,就直接将该str写入文件,无需编码,因为str本身就是一堆二进制的01字节序列。
如果是unicode,那需要先用encode方法将unicode字符串转换为二进制形式的str,才能保存。
重点来了,刚刚我们有提到,unicode -> str是encode过程。既然是encode,肯定需要指定encode的方法,比如最常用的utf-8。坑爹就在于,python2中如果不指定encode的形式,默认是用ASCII码来进行编码。
很明显,ASCII只有128个拉丁字母,是木有处理中文字符能力的。所以报错里面的信息就是ordinal not in range(128)

解决方法很简单,将encode方式指定为utf-8即可。

def t1():f = open("ttt", "w")u1 = u'你好'.encode("utf-8")f.write(u1)t1()

6.UnicodeDecodeError

与UnicodeEncodeError对应的,UnicodeDecodeError肯定就是出现在字节->字符的环节。

def t2():u1 = u"啦啦啦"print repr(u1)byte1 = u1.encode("utf-8")print repr(byte1)byte1.decode("gbk")t2()
u'\u5566\u5566\u5566'
'\xe5\x95\xa6\xe5\x95\xa6\xe5\x95\xa6'
...
UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 8: incomplete multibyte sequence

把一个经过 UTF-8编码后生成的字节序列 '\xe5\x95\xa6\xe5\x95\xa6\xe5\x95\xa6’用GBK解码成unicode的时候,因为GBK编码只有两字节,而UTF-8是三字节,多出来一个字节,肯定无法解析。因此,要防止出现UnicodeDecodeError,主要就是保持编码与解码的时候所用的编码方式一致。

7.coding:utf-8

python代码在开头位置,一般都有这么一行:

# -*- coding: utf-8

作用是定义源代码的编码. 如果没有定义, 此源码中是不可以包含中文字符串的.

8.setdefaultencoding

在源码中经常还可以看到如下代码:

import sys
reload(sys)
sys.setdefaultencoding('utf8')

上面几行代码的作用是设置默认的string的编码格式为utf8,在2.7以后已经不推荐使用这种方式了

参考文献
1.https://zh.wikipedia.org/wiki/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81

python中字符编码:coding utf-8, unicde, defaultencoding, UnicodeDecodeError, UnicodeEncodeError相关推荐

  1. python中字符编码使用_python中字符编码是什么?如何转换字符?

    屏幕前我们看到的文字,在计算机中也是这样表示吗?事实上,我们所有的信息电脑是无法直接理解的,同样我们所要表达的信息,计算机也不能看懂.这就需要架起一个理解的桥梁,也就是编码帮助我们相互之间进行翻译.今 ...

  2. python中字符编码的总结和对比_python2和python3差异总结

    项目马上就要由python2迁移到python3环境所有就简单总结下区别,个人觉得这些差不多,详情见如下吧 核心类差异 Python3 对 Unicode 字符的原生支持 Python2 中使用 AS ...

  3. python中gbk字符原因报错_不想再被鄙视?那就看进来! 一文搞懂 Python 2 字符编码...

    原标题:不想再被鄙视?那就看进来! 一文搞懂 Python 2 字符编码 程序员都自视清高,觉得自己是创造者,经常鄙视不太懂技术的产品或者QA.可悲的是,程序员之间也相互鄙视,程序员的鄙视链流传甚广, ...

  4. (转载)Python常见字符编码间的转换

    Python常见字符编码间的转换 主要内容:     1.Unicode 和 UTF-8的爱恨纠葛     2.字符在硬盘上的存储     3.编码的转换     4.验证编码是否转换正确     5 ...

  5. python转换字符编码_转:Python常见字符编码及其之间的转换

    一.Python常见字符编码 字符编码的常用种类介绍 第一种:ASCII码 ASCII(American Standard Code for Information Interchange,美国信息交 ...

  6. python转换字符编码_Python常见字符编码间的转换

    学习Python,字符编码间的转换是绕不过去的一只拦路虎,不把编码彻底搞明白,总有一天它会猝不及防坑你一把. Python2.x和Python3.x在字符编码的设置上也有很大区别(Python3未来将 ...

  7. Python常见字符编码及其之间的转换

    参考:Python常见字符编码 + Python常见字符编码间的转换 一.Python常见字符编码 字符编码的常用种类介绍 第一种:ASCII码 ASCII(American Standard Cod ...

  8. python:字符编码问题

    摘要 最近用python,遇到了诸多编码问题,曾经看过一个关于字符编码的文章,感觉很好,特意转载出来. 前言 很多程序员对字符编码不太理解,虽然他们大概知道 ASCII.UTF8.GBK.Unicod ...

  9. python安全编码问题_浅谈Python中的编码问题

    对于Python的初学者来说,编码问题相当令人头疼.本文就根据我在学习过程中遇到的问题简单谈一下Python中的编码.首先简单介绍一下几种常见的编码. 一.几种常见的字符编码 ASCII码 ASCII ...

  10. python中的编码问题

    Python 中的编码问题 在python中遇到编码问题主要来自于ASCII和gbk两个方面.win中python为unicode 编码而控制台一般为gbk编码 ASCII 对于ASCII来说,是由于 ...

最新文章

  1. 使用for循环遍历文件
  2. 使用MLX90640自制红外热像仪(二):API函数的使用
  3. XML文档类型定义DTD
  4. 005_Redis的Hash数据类型
  5. 【杂谈】从GitHub上星星最多的男人开始发GitHub综述资料
  6. GIT 中同时 push 代码到多个远程仓库
  7. SAP UI5 应用开发教程之五十六 - SAP UI5 树控件(tree)的开发
  8. SAP Fiori Elements - How complex binding defined in XML view is parsed
  9. 复习深入笔记01:对象/可变与不可变类型/字符编码/闭包
  10. java实践_Java怪异实践
  11. 30 SD配置-主数据-信用管理-分配交货类型的信贷控制
  12. 类与对象 格式小结 java 1202
  13. 为什么换工作?(面试必问问题)
  14. vue 监听state 任意值变化、监听mutations actions
  15. c语言黑色方块字符,打字符号,一个黑的方块怎么打?
  16. Android Studio 开发APP流程
  17. python日历程序编写_Python创建日历实例
  18. 阿里矢量图标iconfont在微信小程序的使用
  19. 关于开发人员申请苹果账号相关事宜
  20. CODING 如何使用 CODING 研发管理系统来敏捷开发

热门文章

  1. 4698. [SDOI2008]Sandy的卡片【后缀数组】
  2. H5 data-* 属性,设置获取方法总结
  3. CentOS6.5 firefox安装flash插件
  4. 命令dd 及简单应用
  5. 在 Go 语言中使用 Log 包--转自GCTT
  6. 8.12. 安装 Elasticsearch 2.3
  7. 最新SMB僵尸网络利用了7个NSA工具,而WannaCry只用了两个……
  8. 从零開始学androidlt;TabHost标签组件.二十九.gt;
  9. Java/Hbase + C云平台架构设计_十项法则
  10. 《如何阅读一本书》总结