Python字符串编码详解
2016-05-12 16:15
639 查看
前言
“字符串”是Python非常常用的一种数据类型,当所有的内容全是英文的时候,世界静好;但是字符串中涉及到中文字符的时候,问题来了…提到Python的字符串编码,我是这样的
不知道多少个夜晚,被Python的编码问题搞的心力交瘁生无可恋。好,现在我就要代表宇宙消灭你!!!
盘古开天辟地
计算机在最初发明的时候,只有127个常用字符被编码到计算机里,也就是26个英文字母大小写、数字、符号等,这种编码称为ASCII码。 每一个ASCII占用1字节的空间。但是当计算机里需要显示中文的时候,ASCII码就不够用了,所以中国就制订了
GB2312编码,将中文编入;同时,如此渊博的中文,一个字节肯定不够表示啊,至少需要2个字节表示。
世界上有上百种语言,日本把日文编入
Shift_JIS里,韩国把韩文编到
Euc-kr里,所以在多语言混合处理的时候,难免会产生混乱。
秩序初现
于是,Unicode字符编码应运而生。Unicode编码将各种语言统一到一套编码里,每个字符占用2个字节的空间(非常偏僻的字符需要用到4个),从而保证不会出现乱码问题,现代的操作系统和大多数编程语言都支持Unicode。
譬如,字母’A’的ASCII码是65,二进制是
0100 0001;’中’的编码已经超过了ASCII,用Unicode编码是20013,二进制是
0100 1110 0010 1101;
>>> ord("A") 65 >>> ord('中') 20013 >>>
而字母’A’使用Unicode编码,只需要在前面补0就可以了,即
0000 0000 0100 0001,所以Unicode是兼容ASCII码的。
发展前行
Unicode消除了乱码问题,新的问题又出现了:Unicode编码的字符占用2字节的存储空间,但如果文本全都是英文的话,使用Unicode比ASCII需要多一倍的存储空间,在存储和传输上就不太划算。所以,UTF-8——可变长的Unicode编码出现了。UTF-8编码将英文字母编码为1个字节,中文字符编码为3个字节,而生僻字则可能使用4-6个字节,这样,在传输和存储的过程中则会更加节省空间。
所以,计算机中这些编码的运行过程是这样的:
在计算机内存中,统一使用Unicode编码
当需要存储或传输时,使用
encode将Unicode编码为UTF-8,如
u'中文'.encode('utf-8')的意思是现有编码为Unicode,encode为参数所指示的编码
当从外存读数据进行运算时,则需要使用
decode将UTF-8编码解码为为Unicode编码,如
'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')的意思是现有编码为参数所指示的编码,decode为Unicode编码
搞清楚了各类编码的关系,接下来需要看看Python中具体的编码问题。
Python2.7中的字符编码
龟叔开发Python的时候,天下大一统的Unicode字符编码还没出来呢,所以最初的Python只支持ASCII编码。后来,才加入了对Unicode的支持,Unicode字符必须要使用u’….’来表示。>>> u'中文'.encode('utf-8') '\xe4\xb8\xad\xe6\x96\x87' >>> u'ABC'.encode('utf-8') 'ABC' >>> print '\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8') 中文
从中可以看出,utf-8编码和Unicode编码中英文字母的显示是一样的,但是如上所述,占用字节不一样,utf-8中占用1字节,而Unicode中占用2字节。
注意:不要使用window下的Python IDLE Shell测试代码,可能是它内部的编码都没有处理好,在cmd命令行中则一切ok。
什么时候会出错呢?
>>> '中文'.encode('utf-8') Traceback (most recent call last): File "<pyshell#3>", line 1, in <module> '中文'.encode('utf-8') UnicodeDecodeError: 'ascii' codec can't decode byte 0xd6 in position 0: ordinal not in range(128)
Bomb!是不是很熟悉,其实就是因为没有把Unicode编码使用u’…’包裹起来,导致系统以为它是ASCII编码,但是ASCII编码只有127个,肯定越界了。搞清楚了各大编码的关系,是不是解决问题就显得很简单(笑脸)?
Python3中的字符编码
在最新的Python 3版本中,字符串是以Unicode编码的,也就是说,我们不需要u’….’对Unicode字符进行包裹了。Python2.7:
>>> '中文' '\xd6\xd0\xce\xc4' >>> u'中文' u'\u4e2d\u6587' >>> print u'中文' 中文 >>> print '中文' 中文
Python 3.5:
>>> '中文' '中文' >>> u'中文' '中文'
由于Python的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。Python对bytes类型的数据用带b前缀的单引号或双引号表示:
>>> b'ABC' b'ABC' >>> b'ABC'.decode('utf-8') 'ABC' >>> '中文'.encode('utf-8') b'\xe4\xb8\xad\xe6\x96\x87' >>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8') '中文'
需要区分b’ABC’与’ABC’,前者是utf-8编码的字节类型,每个字符占用一个字节;而后者是Python的字符串str类型。
在操作字符串时,我们经常遇到str和bytes的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对str和bytes进行转换。
由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码时,为了让它按UTF-8编码读取。
(By MrHammer 2016-05-12 下午4点 @Ningtu Sunny)
相关文章推荐
- numpy初始化数组时遇到的问题
- Python日志输出——logging模块
- Python2.7注意点汇总(至函数模块)
- python里面的list
- python装饰器(decorator)
- 【Python学习笔记】基础
- Python高级爬虫之动态加载页面的解决方案与爬虫代理
- 使用py2exe来打包python脚本到exe程序
- 【语言-Python】Python的带参数调用
- python 第一章 介绍-1.python特点.
- python模块2
- Python中的集合:set与frozenset用法举例
- Python通过Zabbix API获得数据
- Python中遍历字典过程中更改元素导致异常的解决方法
- 283. Move Zeroes [easy] (Python)
- python 的内建函数
- python 基础知识(一)
- Apriori算法简介及实现(python)
- python模块1
- (改)python 仿ab网站压力测试