2015-01-21 66 views
1

一个简单的例子unicode的变量:Python的解码与非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 de故障编码,u'abc'.decode('utf-8')没有错误,但是u'中国'.decode('utf-8')有错误。

    我觉得做u'中国'.decode('utf-8'),Python的检查,发现当u'中国'是unicode的,所以尽量做到u'中国'.encode(sys.getdefaultencoding()),这样会导致问题,而例外的是UnicodeEncodeError,不是错误的时候解码。

    u'abc''abc'(< 128)的代码点相同,所以没有错误。

  2. 在Python 2.x中,python内部存储变量值如何?如果字符串< 128中的所有字符视为ascii,如果> 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

简短的回答

你必须使用encode(),或离开它。不要使用带有unicode字符串的decode(),这没有任何意义。此外,sys.getdefaultencoding()在这里没有任何帮助。

漫长的答案,第1部分:如何正确地做到这一点?

如果定义:

c_u = u'中国' 

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

如果执行:

print c_u.encode() 

您的字符串将被编码回UTF-8和字节串发送到标准输出。请注意,这通常是为您自动发生,所以您可以简化这:

print c_u 

长的答案,第2部分:这有什么错c_u.decode()?

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

  1. 试图将对象转换(即你的unicode字符串),以字节串
  2. 尝试,如果你的对象是摆在首位一个Unicode字符串到字节字符串解码为unicode字符串

请注意,这并没有任何意义 - 你只将它转换回来。但为什么会失败?那么,这是一个Python的奇怪的功能,第一步骤(1),即从unicode字符串任何转换为字节串,通常采用sys.getdefaultencoding(),这反过来又默认为ASCII字符集。换句话说,

c_u.decode() 

大致解释到:

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

这就是为什么它失败。

注意的是,虽然你可能会改变这种默认的编码,不要忘记其他第三方库可能包含类似的问题,如果默认编码为ASCII不同可能打破。

话虽如此,我坚信,Python的是,如果他们没有在第一时间定义unicode.decode()更好。 Unicode字符串已经被解码,再次解码它们毫无意义,特别是Python的方式。

+0

我知道应该使用'encode',我的问题是,为什么在u'abc”使用解码都没有问题,而且我认为是正确的? – 2015-01-21 09:22:09

+0

请参阅我的答案的第二部分,其中描述了unicode.decode()在内部的行为。这应该清楚为什么'u'abc'.decode()'意外地工作。 – vog 2015-01-21 09:38:33

+1

你说的第2部分,我认为错误:'从unicode字符串的任何隐式转换为字节字符串,总是使用ASCII字符set.'。请参阅我问的示例代码,如果将默认编码更改为utf-8,则可以。 – 2015-01-21 14:12:33