Python中的编码问题

虽然有个一般性的 UnicodeError 异常,但是报告错误时几乎都会指明具体的异常:UnicodeEncodeError(把字符串转换成二进制序列时)或 UnicodeDecodeError(把二进制序列转换成字符串时)。如果源码的编码与预期不符,加载 Python 模块时还可能抛出 SyntaxError。接下来说明如何处理这些错误。

1.处理UnicodeEncodeError
多数非 UTF 编解码器只能处理 Unicode 字符的一小部分子集。把文本转换成字节序列时,如果目标编码中没有定义某个字符,那就会抛出 UnicodeEncodeError 异常,除非把 errors 参数传给编码方法或函数,对错误进行特殊处理。下面是用例子进行演示。

>>> city = 'São Paulo'
>>> city.encode('utf_8')   # 'utf_?' 编码能处理任何字符串
b'S\xc3\xa3o Paulo'
>>> city.encode('utf_16')
b'\xff\xfeS\x00\xe3\x00o\x00 \x00P\x00a\x00u\x00l\x00o\x00'
>>> city.encode('iso8859_1')   # 'iso8859_1' 编码也能处理字符串 'São Paulo'
b'S\xe3o Paulo'
>>> city.encode('cp437')   # 'cp437' 无法编码 'ã'(带波形符的“a”)。默认的错误处理方式 'strict' 抛出 UnicodeEncodeError
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/.../lib/python3.4/encodings/cp437.py", line 12, in encode
    return codecs.charmap_encode(input,errors,encoding_map)
UnicodeEncodeError: 'charmap' codec can't encode character '\xe3' in
position 1: character maps to <undefined>
>>> city.encode('cp437', errors='ignore')   # error='ignore' 处理方式悄无声息地跳过无法编码的字符;这样做通常很是不妥
b'So Paulo'
>>> city.encode('cp437', errors='replace')   #  编码时指定 error='replace',把无法编码的字符替换成 '?';数据损坏了,但是用户知道出了问题
b'S?o Paulo'
>>> city.encode('cp437', errors='xmlcharrefreplace')   # 'xmlcharrefreplace' 把无法编码的字符替换成 XML 实体
b'São Paulo'

2.处理UnicodeDecodeError
不是每一个字节都包含有效的 ASCII 字符,也不是每一个字符序列都是有效的 UTF-8 或 UTF-16。因此,把二进制序列转换成文本时,如果假设是这两个编码中的一个,遇到无法转换的字节序列时会抛出 UnicodeDecodeError

另一方面,很多陈旧的 8 位编码——如 'cp1252''iso8859_1''koi8_r'——能解码任何字节序列流而不抛出错误,例如随机噪声。因此,如果程序使用错误的 8 位编码,解码过程悄无声息,而得到的是无用输出。
下面是用例子进行演示。

>>> octets = b'Montr\xe9al'  
>>> octets.decode('cp1252')   # 可以使用 'cp1252'(Windows 1252)解码,因为它是 latin1 的有效超集
'Montréal'
>>> octets.decode('iso8859_7')   # ISO-8859-7 用于编码希腊文,因此无法正确解释 '\xe9' 字节,而且没有抛出错误
'Montrιal'
>>> octets.decode('koi8_r')   #  KOI8-R 用于编码俄文;这里,'\xe9' 表示西里尔字母“И”
'MontrИal'
>>> octets.decode('utf_8')   # 'utf_8' 编解码器检测到 octets 不是有效的 UTF-8 字符串,抛出 UnicodeDecodeError
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 5:
invalid continuation byte
>>> octets.decode('utf_8', errors='replace')   # 使用 'replace'
 错误处理方式,\xe9
 替换成了“[图片上传中。。。(1)]”(码位是 U+FFFD),这是官方指定的 REPLACEMENT CHARACTER
(替换字符),表示未知字符
'Montr􀓠al'

3.使用预期之外的编码加载模块时抛出的SyntaxError
Python 3 默认使用 UTF-8 编码源码,Python 2(从 2.5 开始)则默认使用 ASCII。如果加载的 .py 模块中包含 UTF-8 之外的数据,而且没有声明编码,会得到类似下面的消息:

SyntaxError: Non-UTF-8 code starting with '\xe1' in file ola.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

GNU/Linux 和 OS X 系统大都使用 UTF-8,因此打开在 Windows 系统中使用 cp1252 编码的 .py 文件时可能发生这种情况。注意,这个错误在 Windows 版 Python 中也可能会发生,因为 Python 3 为所有平台设置的默认编码都是 UTF-8。
为了修正这个问题,可以在文件顶部添加一个coding 注释

# coding: cp1252

print('Olá, Mundo!')

现在,Python 3 的源码不再限于使用 ASCII,而是默认使用优秀的 UTF-8 编码,因此要修正源码的陈旧编码(如 'cp1252')问题,最好将其转换成 UTF-8,别去麻烦 coding 注释。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容