python 字符编码

1.Python Unicode字符串
字符串还有一个编码问题。
由于计算机只能处理数字,若是要处理文本,就必须先把文本转换为数字才能处理。*先的计算机在设计时采用8个比特(bit)做为一个字节(byte),因此,一个字节能表示的*大的整数就是255(二进制11111111=十进制255),0 – 255被用来表示大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,好比大写字母 A 的编码是65,小写字母 z 的编码是122。
若是要表示中文,显然一个字节是不够的,至少须要两个字节,并且还不能和ASCII编码冲突,因此,中国制定了GB2312编码,用来把中文编进去。
相似的,日文和韩文等其余语言也有这个问题。为了统一全部文字的编码,Unicode应运而生。Unicode把全部语言都统一到一套编码里,这样就不会再有乱码问题了。
Unicode一般用两个字节表示一个字符,原有的英文编码从单字节变成双字节,只须要把高字节所有填为0就能够。
由于Python的诞生比Unicode标准发布的时间还要早,因此*先的Python只支持ASCII编码,普通的字符串’ABC’在Python内部都是ASCII编码的。
Python在后来添加了对Unicode的支持,以Unicode表示的字符串用u’…’表示,好比:
print u’中文’
中文
注意: 不加 u ,中文就不能正常显示。
Unicode字符串除了多了一个 u 以外,与普通字符串没啥区别,转义字符和多行表示法仍然有效:
转义:
u’中文\n日文\n韩文’
多行:
u”’*行
第二行”’
raw+多行:
ur”’Python的Unicode字符串支持”中文”,
“日文”,
“韩文”等多种语言”’
若是中文字符串在Python环境下遇到 UnicodeDecodeError,这是由于.py文件保存的格式有问题。能够在*行添加注释
# -*- coding: utf-8 -*-
目的是告诉Python解释器,用UTF-8编码读取源代码。而后用Notepad++ 另存为… 并选择UTF-8格式保存。

2.解析unicode编码的字符串
使用python抓取页面或者web端的json时候很容易抓到一些unicode编码的字符串流。在python里边对Unicode编码的处理成了一件头疼的事。

对于string里边不含”引号的处理比较简单,使用eval注明引入str是unicode编码:

str1 = eval(“u”+”\””+str + “\””)

str1.decode(‘utf8’)
对于包含引号的明文,须要先把引号转化为 \”,而后能够进行eval函数处理。 web

str=str.replace(“\\\””,”\\\\\””) #先转化字符串中的\”
str=str.replace(“\””,”\\\””) #再转化 ”

print eval(“u”+”\””+str+”\””)
对于json格式unicode的有个很奇怪的处理:

python 的json 库在使用 json.loads()函数时候会默认把输入中unicode编码解析好,而不是保留原输入。 函数

代码: 编码

str1=”{\”html\”:\”\u003c\u003e\”}”
s=json.loads(str1)
print s[“html”]
输出:<>
输出<>而不是 \u003c 这也引出了一个问题:python的json库解析json不彻底保留原格式,使用时候要注意。

若是想要json解析保持unicode编码比较麻烦,需要将unicode码的\改成\\,转译代码以下:

str=”{\”html\”:\”\u003c\”}”
s=str.replace(“\\u”,”\\\\u”)
s2=json.loads(s)
print s2[“html”]
输出: \u003c
3.str字符串和unicode字符串
字符编码
咱们在编辑器中输入的文字,对用户来讲是可读的。可是机器只能读懂01串,那怎么把咱们方便阅读的符号转换成机器能读懂的01串呢?程序员

这就需要给出符号-二进制之间的映射关系,并且必须是一一映射:即给定一个符号,机器有并且有惟一的二进制对应。根据字符获得二进制表示是编码过程(encode);根据二进制表示获得字符是解码过程(decode)。web

ASCII字符集与字符编码
刚开始的时候,给出了ASCII标准,用一个8bits字节来表示字符。并且这个字节实际上只用了7位,*高位是不用的,这样总共能表示128个字符。意味着ASCII字符集只有128个。数据库

随着计算机的普及,愈来愈多的国家开始使用计算机。128个字符难以知足各个国家的语言需求,这促使包含更多字符的字符集诞生,而且须要采用新的编码方案。网络

Latin-1
充分利用8bits字节的高位,扩展到256个字符。编辑器

Unicode字符集与字符编码
Unicode字符集包含了全部种语言的全部字符。一般用U+后接4位的16进制数字表示一个Unicode字符,好比U+FFFF。svg

UTF-8编码
UTF-8是针对Unicode字符集的一种编码方案。编码

用变长字节来表示字符:有的字符用一个字节表示(好比ASCII中规定的字符),有的字符用2个字节表示。*大长度为4字节。spa

%title插图%num

上面这张图是从Wikipedia中截取的。Number of Bytes列表示字节数;Bits for code point列表示多少个bit位是真正有用的;First code point列表示该字节数能表示的*个Unicode字符;Last code point列表示对应字节数能表示的*后一个Unicode字符;Byte i(i=1,2,3,4)列表示第i字节上的bit值。
以第二行为例,这一行的编码需要两个字节,其中真正有用的bit位只有11个,另5位是占位符,能表示从U+0080~U+07FF的Unicode字符。code

至于具体的编码方式,咱们以欧元符号€为例。€在Unicode字符集中对应U+20AC:

U+20AC位于U+0800~U+FFFF之间,因此须要三个字节来表示;
十六进制20AC能够写成二进制:0010 0000 1010 1100;
前4个bit放在*字节的低4位:11100010;
中间6个bit放在第二字节的低6位:10000010;
后6个bit放在第三字节的低6位:10101100;
因而€的UTF-8编码为:11100010 10000010 10101100。
Unicode字符集还有其余的编码方式,这里就介绍到这里。

要记住:全部的编码方式都是向后兼容ASCII的。ASCII字符对应什么二进制,那么在其余编码方式中也对应一样的二进制。

3.Python的字符串类型
Python包含两种字符串类型:str(其实就是二进制)和unicode。当只会用到ASCII字符集时,一切相安无事。一旦出现其余字符集,问题也就接踵而来。因此下面咱们着重介绍非ASCII字符串。

str类型
咱们平时写的用引号括起来的字符串都是str类型的。
<span style=”color:#000000″>>>> x = <span style=”color:#219161″><span style=”color:#219161″>’哈哈'</span></span>
>>> x
<span style=”color:#219161″><span style=”color:#219161″>’\xb9\xfe\xb9\xfe'</span></span></span>
根据上面的打印结果,能够知道str类型的x存的实际上是二进制序列,而非字符串。为何会出现这种状况呢?咱们赋给x的明明是字符串。

其实很简单,x通过了一次隐形的编码过程encode()。应该采用的是系统默认编码方案。
– unicode类型
若是在引号的前面加上字符u,那么咱们就获得一个unicode字符串:

<span style=”color:#000000″>>>> x = <span style=”color:#219161″><span style=”color:#219161″>u’哈哈'</span></span>
>>> x
<span style=”color:#219161″><span style=”color:#219161″>u’\u54c8\u54c8′</span></span></span>
unicode对象保存的是字符串自己,而非二进制序列。好比程序中的unicode字符串中包含两个U+54c8字符。

unicode编码为str
可是有的时候,咱们须要二进制序列,好比将数据写入文件、发送到网络或者写入数据库中时。若是不进行任何处理,会出现错误:

<span style=”color:#000000″>>>> x = <span style=”color:#219161″><span style=”color:#219161″>u’哈哈'</span></span>
>>> x
<span style=”color:#219161″><span style=”color:#219161″>u’\u54c8\u54c8′</span></span>
>>> f = open(<span style=”color:#219161″><span style=”color:#219161″>’test.txt'</span></span>, <span style=”color:#219161″><span style=”color:#219161″>’w'</span></span>);
>>> f.write(x)
Traceback (most recent call last):
File <span style=”color:#219161″><span style=”color:#219161″>”<stdin>”</span></span>, line <span style=”color:#40a070″><span style=”color:#40a070″>1</span></span>, <span style=”color:#954121″><span style=”color:#954121″>in</span></span> <module>
UnicodeEncodeError: <span style=”color:#219161″><span style=”color:#219161″>’ascii'</span></span> codec can<span style=”color:#219161″><span style=”color:#219161″>’t encode characters in position 0-1: ordinal not in range(128)</span></span></span>
这是由于在把字符串写入文件时,会首先检查字符串的类型,若是是str类型的字符串,那么一切OK;若是是unicode类型的字符串,那么会隐式地对其编码,即x.encode()。而系统默认的编码方案是ASCII(能够经过sys.getdefaultencoding()查看),对非ASCII字符进行编码的时候,确定会出现错误。

为了不错误,在写入文件以前,应该用utf-8或者gbk编码方案对unicode字符串编码:

<span style=”color:#000000″>>>> x = <span style=”color:#219161″><span style=”color:#219161″>u’哈哈'</span></span>
>>> x
<span style=”color:#219161″><span style=”color:#219161″>u’\u54c8\u54c8′</span></span>
>>> f = open(<span style=”color:#219161″><span style=”color:#219161″>’test.txt'</span></span>, <span style=”color:#219161″><span style=”color:#219161″>’w'</span></span>);
>>> x = x.encode(<span style=”color:#219161″><span style=”color:#219161″>’utf-8′</span></span>) <span style=”color:#408080″><em><span style=”color:#408080″><em>#unicode -> str</em></span></em></span>
>>>x
<span style=”color:#219161″><span style=”color:#219161″>’\xe5\x93\x88\xe5\x93\x88′</span></span>
>>> f.write(x)</span>
str解码为unicode
当从文本中读取数据时,读到的是str字符串,并且咱们已经知道,它保存的是二进制序列。若是其中包含非ASCII文本,咱们应该怎么恢复呢?这时候就要用到解码decode()。

<span style=”color:#000000″>>>> f = open(<span style=”color:#219161″><span style=”color:#219161″>’test.txt'</span></span>, <span style=”color:#219161″><span style=”color:#219161″>’w'</span></span>);
>>> x = f.read()
>>> x
<span style=”color:#219161″><span style=”color:#219161″>’\xe5\x93\x88\xe5\x93\x88′</span></span>
>>> x = x.decode(<span style=”color:#219161″><span style=”color:#219161″>’utf-8′</span></span>) <span style=”color:#408080″><em><span style=”color:#408080″><em>#str -> unicode</em></span></em></span>
>>> x
<span style=”color:#219161″><span style=”color:#219161″>u’\u54c8\u54c8′</span></span></span>
必定要记得,用什么方式编码的就必须用什么方式解码。否则的话,从二进制到字符的对应过程会出现UnicodeDecodeError。

print语句
print语句的参数须要是str类型,并且在执行的时候会用系统的编码方式对str进行隐式解码。

两个遗留问题
#-*-coding:utf-8 -*-
如今暂且认为若是脚本中包含中文,那么必须加上这个声明。

setdefaultencoding() 这个方法貌似如今不能够用了。我以为这个设置与encode()、decode()在不指明参数的状况下的默认参数有关。