如何在Python中将unicode转换为字符串?
以下的unicode和字符串如果明确地定义,可以单独存在:
>>> value_str='Andr\xc3\xa9'
>>> value_uni=u'Andr\xc3\xa9'
如果我只有像上面那样把 u'Andr\xc3\xa9'
赋值给一个变量,我该如何在Python 2.5或2.6中将其转换为 'Andr\xc3\xa9'
呢?
编辑:
我做了以下操作:
>>> value_uni.encode('latin-1')
'Andr\xc3\xa9'
这解决了我的问题。有人能给我解释一下到底发生了什么吗?
7 个回答
你在评论中问:“这让我很困惑。它是怎么从最初的带重音字符变成现在这样的?当你说用utf8和latin1进行了双重编码时,是不是总共编码了3次(2次utf8 + 1次latin1)?从原始状态到现在的编码顺序是什么?”
在Mark Byers的回答中,他提到:“你所拥有的似乎是一个被错误解码的UTF-8编码。”你接受了他的回答,但还是觉得困惑?好吧,下面我会详细解释一下:
注意:所有字符串将使用(隐式地)repr()
显示。unicodedata.name()
将用于验证内容。这样,控制台编码的变化就不会影响字符串的解释。
初始状态:你有一个名为u1的unicode对象。它包含了e-acute字符:
>>> u1 = u'\xe9'
>>> import unicodedata as ucd
>>> ucd.name(u1)
'LATIN SMALL LETTER E WITH ACUTE'
你将u1编码为UTF-8,并将结果命名为s:
>>> s = u1.encode('utf8')
>>> s
'\xc3\xa9'
你用latin1解码s——这是错误的;s是用utf8编码的,而不是latin1。结果就是一些毫无意义的垃圾。
>>> u2 = s.decode('latin1')
>>> u2
u'\xc3\xa9'
>>> ucd.name(u2[0]); ucd.name(u2[1])
'LATIN CAPITAL LETTER A WITH TILDE'
'COPYRIGHT SIGN'
>>>
请理解:unicode_object.encode('x').decode('y')
当x和y不同时,通常是没有意义的;如果你运气好,它会抛出异常;如果运气不好,它会默默地生成一些无意义的东西。还要明白,默默生成无意义的东西并不是一个bug——没有通用的方法可以让Python(或其他语言)检测出这种无意义的情况。这尤其适用于latin1,因为所有256个代码点与前256个Unicode代码点一一对应,所以从str_object.decode('latin1')中不可能得到UnicodeDecodeError。
当然,异常情况下(希望这不是常态),你可能需要通过执行gibberish_unicode_object.encode('y').decode('x')
来逆转这种无意义的情况,这在你问题的各种回答中都有提到。
如果你有 u'Andr\xc3\xa9'
这个字符串,它是一个Unicode字符串,这个字符串是从一个编码错误的字节字符串解码过来的。正确的编码方式是UTF-8。为了把它转换回字节字符串,这样你就可以正确解码,你可以使用你发现的小技巧。Unicode的前256个编码点和ISO-8859-1(也叫 latin1
)编码是一一对应的。所以:
>>> u'Andr\xc3\xa9'.encode('latin1')
'Andr\xc3\xa9'
现在它变成了一个字节字符串,可以用 utf8
正确解码:
>>> 'Andr\xc3\xa9'.decode('utf8')
u'Andr\xe9'
>>> print 'Andr\xc3\xa9'.decode('utf8')
André
一步到位:
>>> print u'Andr\xc3\xa9'.encode('latin1').decode('utf8')
André
看起来你在编码上搞混了。你真正想要的可能是 u'Andr\xe9'
,这和 'André'
是一样的。
但你现在的内容似乎是一个错误解码的UTF-8编码。你可以通过把这个unicode字符串转换成普通字符串来修复它。我不太确定最好的方法是什么,但这个方法似乎有效:
>>> ''.join(chr(ord(c)) for c in u'Andr\xc3\xa9')
'Andr\xc3\xa9'
然后正确解码:
>>> ''.join(chr(ord(c)) for c in u'Andr\xc3\xa9').decode('utf8')
u'Andr\xe9'
现在它就变成正确的格式了。
不过,如果可以的话,建议你先弄清楚数据为什么会被错误编码,然后在源头解决这个问题。