Python 编码问题——UnicodeDecodeError(二)

我的上一篇博客 Python 编码问题——UnicodeDecodeError(一)基本上足够应对常见Python Unicode编码错误问题,主要解释了问题产生的原因——隐式编码解码机制、避免问题的原则——Unicode“空气锁”原则。本篇主要作为一个补充,便于更好地理解第一篇文章。

一,编码概述

关于Python编码,你最需要了解ASCII,Unicode,UTF-8。

ASCII——1968年诞生,表示范围0-127,比如a的ascii编码为01100001,十进制的97。显然,这个编码范围无法覆盖很多特殊字符比如中文,于是各国纷纷扩展了编码方式,形成自己的编码,如GB2312,GBK,BIG5 Latin1。

Unicode——不同国家编码各自为政,不便于国际化。国际标准化组织制定了Unicode编码方式。Unicod只是一个码表,具体怎么实现并没有强制规定,比如规定了a=97,但你可以用01100001,也可以用0000000001100001表示——这个发挥空间就产生了UTF-8,UTF-16,UTF-32等编码方式。

UTF-8——各国常用文字通常2个字节即16位就足够表示了,但欧美字符很少,一般一个字节就足够了,如果使用两个字节统一编码就浪费了。为了节省空间,UTF-8采用一种变长编码方式:

0xxxxxxx,以0开头表示把一个字节做为一个单元,就跟ASCII完全一样

110xxxxx 10xxxxxx.如果是这样的格式,则把两个字节当一个单元

1110xxxx 10xxxxxx 10xxxxxx 如果是这种格式则是三个字节当一个单元.

注意,在python中,unicode是一种数据类型而不完全等同于这里说的Unicode编码,对于unicode类型,用\uxxxx的方式表示(unicode类型可以理解为python内存编码形式,也是一种Unicode编码);对于utf-8编码,用\xaa\xbb\xcc的方式表示。

二,Python源文件字符编码

 python源文件默认字符编码是ASCII,所以如果在python文件中不显示的指定编码格式的话,出现非ASCII字符将出现语法错误,比如说中文。如果在需要在源码中使用中文,必须在源文件的第一行或者第二行显示地指定编码格式。注意,这里只是这个源码文件自身的编码方式,而不表示python在处理字符串时用的编码方式。

扫描二维码关注公众号,回复: 4591077 查看本文章

# coding=utf-8

或者

#!/usr/bin/python

# -*- coding: utf-8 -*-

三,python字符串编码

Python字符串的数据类型有两种——str和unicode,它们均继承自basestring。

str是unicode经过编码后的字节组成的序列,str类型的字符其具体的编码格式和操作系统有关系。默认地,windows采用gbk编码,Linux和mac采用utf-8.

Windows:

>>>b = "故乡"
>>>b
'\xb9\xca\xcf\xe7'

Linux或者mac:

>>>b = "故乡"
>>>b
'\xe6\x95\x85\xe4\xb9\xa1'

创建unicode字符串需要用 u"字符串" 。

Windows:

>>> s = u"故乡"
>>> s
u'\u6545\u4e61'

Linux或者mac:

>>> s = u"故乡"
>>> s
u'\u6545\u4e61'

我们发现,当使用unicode编码时,不同平台表示形式统一了。unicode的这种特性可以作为在程序中的中间编码,比如将utf8编码的str转为gbk编码:a.decode('utf8').encode('GBK')。转换需要注意两个点:

1,只有str才能被decode,只有unicode才能被encode

2,只有str原本是用utf-8编码的,才能用utf-8来decode

>>> b.decode('utf-8')
u'\u6545\u4e61'
>>> s.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

上面两点是很多错误的根源。其中尤其是第2点,python2的默认编码方式是ascii(可以用sys.getdefaultencoding()函数查看),asscii在0-127范围内和utf-8是一模一样的,因为在数字和英文字符的解码上没有问题,但是在中文字符的解析时可能出现问题。这就导致平时我们可能觉得没有问题的地方,突然有一天有一个特殊字符过来发现有问题。

另外一个小知识点:str(s)和unicode(s)是两个工厂方法,分别返回str字符串对象和unicode字符串对象,str(s)是s.encode(sys.getdefaultencoding())的简写,unicode(s)是s.decode(sys.getdefaultencoding())的简写。

4, unicode-escape

创建unicode字符串需要在字符串前加u告诉python编译器后边的字符串需要转换成unicode字符,这个过程是编译器做的,加上u本质上就等于 “xxx”.decode(sys.getdefaultencoding()),但如果我们已知unicode编码'\u6545\u4e61',怎么将它还原为unicode编码的字符串呢?

>>>'\u6545\u4e61'.decode("unicode-escape")
u'\u6545\u4e61'

或者:

>>>unicode('\u6545\u4e61',"unicode-escape")
u'\u6545\u4e61'

还可以这样:

>>> s = '\u6545\u4e61'
>>> print(eval("u\'"+s+"\'"))
故乡

print 函数要想打印出正确的字符,传入的参数要么是本地编码格式编码的字符串,要么是unicode字符串。

参考 : https://blog.csdn.net/trochiluses/article/details/16825269

https://www.cnblogs.com/chownjy/p/6625299.html

猜你喜欢

转载自blog.csdn.net/hongxingabc/article/details/82763445