网站开发工程是待遇,中国去中心化搜索引擎,山东线上推广软件,效果图制作公司赚钱吗Python中的字符编码与解码困扰了我很久了#xff0c;一直没有认真整理过#xff0c;这次下静下心来整理了一下我对方面知识的理解。
文章中对有些知识没有做深入的探讨#xff0c;一是我自己也没有去深入的了解#xff0c;例如各种编码方案的实现方式等#xff1b;二是我觉…Python中的字符编码与解码困扰了我很久了一直没有认真整理过这次下静下心来整理了一下我对方面知识的理解。
文章中对有些知识没有做深入的探讨一是我自己也没有去深入的了解例如各种编码方案的实现方式等二是我觉得只要提能对理解Python字符编码与解码的关键知识即可想深入可以查其它资料。
文中的观点肯定有纰漏只做参考欢迎指正。
Unicode
Unicode是什么这里不多说了百科上面讲的很清楚了这里只提下有助于理解本文主题的知识。
Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。每个字符都对应一个编号编号的范围是0-0x10FFFF来。
字符编码方案
我们知道每个Unicode字符对应一个编号例如汉字“我”对应的编号是25105但在程序中不是直接用编号来表示Unicode字符的那得有多长的数字啊而是表示成16进制格式但具体怎么转换成16进制不同的编码方案采用的方式不一样。s u我ord(s)
25105s
u\u6211s.encode(utf-8)
\xe6\x88\x91s.encode(utf-16)
\xff\xfe\x11bs.encode(utf-32)
\xff\xfe\x00\x00\x11b\x00\x00s.encode(gbk)
\xce\xd2我们用unicode()内置函数创建了一个Python中的unicode字符然后ord()函数可以得到它在Unicode字符集中的编号。Python的unicode对象有一个encode()方法用来对unicode对像进行编码。
这个示例中的一些知识在后面会讲到现在不用深究。这里提下UTF-8编码方式其它的还没深入研究过但不妨碍本文的主题。
UTF-8以字节为单位对Unicode编号进行编码。每个字节被转换成一个二位的十六进制数。UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。
Python支持很多的编码方案包括asciiutf-8utf-16utf32gbkgb2312等完整的列表可以在下面的链接中找到
http://docs.python.org/2/library/codecs.html#standard-encodings
Python中的字符串
在Python中str 对象表示所有普通字符串对象它只能表示ASCII码表中的字符特点是每个字符占用一个字节所以也叫做字节字符串Byte string。unicode 对象则可以表示所有Unicode字符集中的字符。
s I love python
u u我爱Python
print isinstance(s, str)
print isinstance(u, unicode)
--输出
True
True
还可以使用 str() 函数 和 unicode() 从一个对象构建字符串
str(object) 函数返回的结果通常可以通过定义 object 的 str 属性来定制返回的结果。
unicode()函数接受多个参数与编码格式有关这在后面会讲到。
Python中的Unicode 转义字符
我们常看到“ \u6211” 这样的字符用json.dumps(obj)时如里obj是unicode字符包含非ASCII码且ensure_asciiTrue,那返回的结果字符串中就包含这种形式。这是个转义字符表示Unicode字符“我”。但是注意的是这种转义只在unicode字面量中有效用print 输出时会自动转为对应的unicode字符。而在str字面量中没有特殊意义。web信息中常会遇到“\u4f60\u597d”类型的字符。首先’\u‘开头就基本表明是跟unicode编码相关的。python里str.decode()和str.encode()为我们提供了解码和编码的方法。其中str.decode(unicode_escape)能将此种字符串解码为unicode字符串。下面是在ubuntu的ipython中的操作a u你好a
u\u4f60\u597dprint a
你好b 你好b
\xe4\xbd\xa0\xe5\xa5\xbdprint b
你好c \u4f60\u597dc
\\u4f60\\u597dprint c
\u4f60\u597dd r\u4f60\u597dd
\\u4f60\\u597dprint d
\u4f60\u597dd c
Truee c.decode(unicode_escape)e
u\u4f60\u597dprint e
你好其实6211是字符‘我’在Unicode字符集中的编号25105的16进制值
字符串字面量和程序中处理的字符串
在源代码中字符串通常用字面量来表示
u u我爱Python
但字面量是给人看的程序看到的是对字面量进行处理后的字符而且 str 字符串和 unicode 字符串的处理方式不一样。
unicode 字符串会将字面量中的非ASCII字符替换成Unicode转义符但最后的结果是与原字符串等价的。
str类型的字面量会使用设置的编码格式进行编码处理最后得到的是编码字符串这点很重要后面会提到。编码字符串与原字符串不能等同。
--脚本
-- coding: utf-8 --
s 我爱Python
u u我爱Python
print encoded str: , repr(s)
print escaped unicode: , repr(u)
print str: , s
print decoded str: , s.decode(utf-8)
print unicode: , u
--输出
encoded str: \xe6\x88\x91\xe7\x88\xb1Python
escaped unicode: u\u6211\u7231Python
str: 鎴戠埍Python
decoded str: 我爱Python
unicode: 我爱Python
\xe6\x88\x91\xe7\x88\xb1Python是对 s 编码后的编码字符串直接输出编码字符串会得到不一样的结果因为实际上\xe6 等被当作16进制转义字符来处理了。要想得到正确结果需要先解码。
u\u6211\u7231Python是转义后的与 u 等价的unicode字符串
编码字符串
编码字符串是指采用指定的编码格式对字符进行编码后得到的字符串。编码格式有很多中例如 ascii、utf-8、gbk、gbk2312等。
编码字符串是纯 str 字符串它表示原字符串的编码结果。直接输出编码字符串可能会与原来的字符串表示的值不一样除非原来的字符串都是ASCII字符。
--脚本
-- coding: utf-8 --
s 我
s1 我爱Python
print len(s)
print repr(s)
print s
print repr(s1)
print s1
--输出
3
\xe6\x88\x91
我
\xe6\x88\x91\xe7\x88\xb1Python
鎴戠埍Python
\xe6\x88\x91 和 \xe6\x88\x91\xe7\x88\xb1Python 就是编码字符串。在编码字符串中类似 \xe6 这种字符是Python中的16进制转义字符被看作是一个字符而不是4个字符。Python转义序列http://docs.python.org/2/reference/lexical_analysis.html#string-literals
我们可以看到 s 的长度已经是3了因为这里统计的是编码字符串的长度。
上面的例子有个小细节字符串只包含单个字符的时候print语句好像做了解码处理能直接输出正确的结果但多个字符就会乱码。
这是为什么呢
开始编码和解码
前面介绍了一些基本知识现在开始来对字符串进行编码和解码了。
编码
--脚本
-- coding: utf-8 --
u u我爱Python
print encoded[utf-8]: , repr(u.encode(utf-8))
print encoded[gbk]: , repr(u.encode(gbk))
print encoded[ascii]: , repr(u.encode(ascii))
--输出
encoded[utf-8]: \xe6\x88\x91\xe7\x88\xb1Python
encoded[gbk]: \xce\xd2\xb0\xaePython
encoded[ascii]:
Traceback (most recent call last):
File C:\Users\chw\Desktop\encoding.py, line 8, in print encoded[ascii]: , repr(u.encode(ascii))
UnicodeEncodeError: ascii codec cant encode characters in position 0-1: ordinal not in range(128)
在上面的例子中我们对一个unicode字符串采用了不同编码方式进行了编码打印编码字符串。最后我们得到了一个错误是因为ascii编码格式不能编码非ASCII字符。
对于str类型的字面量程序会自动做编码处理所以就不要再去编一次码了。至于程序会采用何种编码格式要看设置例如在前面的脚本中开头都有一个编码格式声明
-- coding: utf-8 --
这个声明告诉编译器该用什么编码格式处理str类型的字面量。在Python2.6以后的版本好像会根据保存源代码文件的格式来判断编码格式没有声明的情况下但先不深究了总之开头指定编码格式应该是个好习惯。
解码
str对象提供decode()方法来解码
--脚本
-- coding: utf-8 --
s 我爱Python
print repr(s)
print s
print s.decode(utf-8)
--输出
\xe6\x88\x91\xe7\x88\xb1Python
鎴戠埍Python #乱码了
我爱Python
前面我们讲过str 字面量被自动编码成编码字符串所以这里的 s 已经是编码后的编码字符串了因此要输出 s 原来的字符就需要解码。而开始我们指定了源文件的编码方式为utf-8所以我们需要用utf-8格式来解码。
IDLE交互环境中的差异
在IDLE交互环境中Unicode字面量好像不能正确的工作u u我爱Pythonu
u\xce\xd2\xb0\xaePythonisinstance(u, unicode)
Trueprint u
ÎÒ°®Python此例中u实际上是表示我爱Python的编码字符串的unicode字符串而不是我爱Python的unicode字符串了。也就是说先将我爱Python编码成编码字符串然后把编码字符串转换成unicode字符串。
在IDLE 交互环境中创建unicode对象的正确方式应该是下面这样u unicode(我爱Python, gbk)print repr(u)
u\u6211\u7231Pythonprint u
我爱Python
unicode函数的第一个参数指定编码字符串第二个参数指定这个编码字符串的编码格式。函数在处理中先用第二个参数指定的编码格式解码第一个参数根据不同的编码格式可以直接返回一个unicode字符串。
如果省略第二个参数unicode函数会将ascii作为默认编码格式不管是交互环境还是脚本中都是这样。
第二个参数的值与你的环境配置有关我在windows下面使用IDLE交互环境默认的编码是gbk或者是gbk兼容的编码格式。
在脚本中unicode字面量能被解析成正确的unicode字符串没有IDLE那种令人费解的问题
---脚本
-- coding: utf-8 --
u u我爱Python
print repr(u)
print unicode: , u
---输出
u\u6211\u7231Python
unicode: 我爱Python