Python在unicode变量中解码,带有非ascii字符或没有

时间:2015-01-21 08:21:22

标签: python unicode encoding utf-8 ascii

一个简单的例子:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import traceback

e_u = u'abc'
c_u = u'中国'

print sys.getdefaultencoding()
try:
    print e_u.decode('utf-8')
    print c_u.decode('utf-8')
except Exception as e:
    print traceback.format_exc()

reload(sys)
sys.setdefaultencoding('utf-8')
print sys.getdefaultencoding()
try:
    print e_u.decode('utf-8')
    print c_u.decode('utf-8')
except Exception as e:
    print traceback.format_exc()

输出:

ascii
abc
Traceback (most recent call last):
  File "test_codec.py", line 15, in <module>
    print c_u.decode('utf-8')
  File "/System/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)

utf-8
abc
中国

有些问题困扰我几天,当我想彻底了解python中的编解码器时,我想确定我认为是对的:

  1. ascii默认编码下,u'abc'.decode('utf-8')没有错误,但u'中国'.decode('utf-8')有错误。

    我认为什么时候u'中国'.decode('utf-8'),Python检查并发现u'中国'是unicode,所以它尝试u'中国'.encode(sys.getdefaultencoding()),这会导致问题,例外是UnicodeEncodeError ,解码时不会出错。

    u'abc''abc'(&lt; 128)具有相同的代码点,因此没有错误。

  2. 在Python 2.x中,python内部存储变量值如何?如果字符串中的所有字符都是&lt; 128,视为ascii,如果&gt; 128,视为utf-8

    In [4]: chardet.detect('abc')
    Out[4]: {'confidence': 1.0, 'encoding': 'ascii'}
    
    In [5]: chardet.detect('abc中国')
    Out[5]: {'confidence': 0.7525, 'encoding': 'utf-8'}
    
    In [6]: chardet.detect('中国')
    Out[6]: {'confidence': 0.7525, 'encoding': 'utf-8'}
    

1 个答案:

答案 0 :(得分:1)

简短回答

您必须使用encode(),否则请将其删除。不要将decode()与unicode字符串一起使用,这没有任何意义。此外,sys.getdefaultencoding()无论如何也无法提供帮助。

长答案,第1部分:如何正确完成?

如果你定义:

c_u = u'中国'

然后c_u已经是一个unicode字符串,也就是说,它已经使用你的-*- coding: utf-8 -*-声明由Python解释器从字节字符串(源文件)解码为unicode字符串。

如果您执行:

print c_u.encode()

您的字符串将被编码回UTF-8,并且该字节字符串将被发送到标准输出。请注意,这通常会自动发生,因此您可以将其简化为:

print c_u

答案很长,第2部分:c_u.decode()有什么问题?

如果执行c_u.decode(),Python将

  1. 尝试将您的对象(即您的unicode字符串)转换为字节字符串
  2. 尝试将该字节字符串解码为unicode字符串
  3. 请注意,如果您的对象首先是一个unicode字符串,那么这没有任何意义 - 您只需将其转换回来。但为什么会失败呢?嗯,这是Python的一个奇怪功能,第一步(1.),即从unicode字符串到字节字符串的任何隐式转换,通常使用sys.getdefaultencoding(),而sys.getdefaultencoding()依次默认为ASCII字符集。换句话说,

    c_u.decode()
    

    大致翻译为:

    c_u.encode(sys.getdefaultencoding()).decode()
    

    这就是它失败的原因。

    请注意,虽然您可能想要更改默认编码,但请不要忘记其他第三方库可能包含类似问题,如果默认编码与ASCII不同,可能会中断。

    话虽如此,我坚信如果Python首先没有定义unicode.decode()会更好。 Unicode字符串已经被解码,再次解码它们没有意义,特别是以Python的方式。