Python中的Unicode字符串和UTF-8有什么关系?

7

我从图书馆获得了一个看起来是不正确的Unicode字符串:

>>> title
u'Sopet\xc3\xb3n'

现在,这两个十六进制转义序列是U+00F3 LATIN SMALL LETTER O WITH ACUTE的UTF-8编码。就我所知,在Python中,Unicode字符串应该包含实际字符,而不是字符的UTF-8编码,所以我认为这是不正确的,可能是库中的错误或输入中的错误,对吗?
问题是,我怎么样才能(a)识别我的Unicode字符串中是否有UTF-8编码的文本,以及(b)将其转换为正确的Unicode字符串?
我卡在了(a)上,因为从编码上来说,原始字符串没有任何问题(即,它们都是有效的字符,u'\xc3\xb3' == ó,但它们不是应该出现的字符)。
看起来,我可以通过eval()那个repr()输出减去前面的"u"来获取一个str,然后使用UTF-8对该str进行解码来实现(b)。
>>> eval(repr(title)[1:]).decode("utf-8")
u'Sopet\xf3n'
>>> print eval(repr(title)[1:]).decode("utf-8")
Sopetón

但是这个方法看起来有些笨拙。是否有一种官方认可的方法可以从Unicode字符串中获取原始数据,并将其作为常规字符串处理?

2个回答

11

a) 尝试按照以下方法进行处理。

b)

>>> u'Sopet\xc3\xb3n'.encode('latin-1').decode('utf-8')
u'Sopet\xf3n'

1
注意1)没有通用的方法来识别utf-8;这将识别它,因为UTF-8解码器将检查其接收到的所有多字节序列是否有效,如果有任何无效的序列,则会引发异常。2)编码为Latin-1的技巧之所以起作用,是因为您的代码点都小于256,Unicode的代码点0-255恰好对应于Latin-1的表示。 - Owen S.
我不确定我完全理解你的评论。也许一个具体的反例会有所帮助。就我所知,".encode('latin-1')"除了结果是str而不是unicode之外,没有任何作用。是否存在一个字符串,使得这种情况不成立?我同意,没有一般方法可以检测unicode字符串中的UTF-8,因为UTF-8编码的字节在unicode字符串中将具有有效(如果不正确)的解释。对于我的目的,我现在只对latin-1感兴趣,所以这已经足够了。 - Watts
@Watts:u'\u03b5\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac'的意思是希腊语。.encode('latin1') - tzot

8
你应该使用:

你应该使用:

>>> title.encode('raw_unicode_escape')

Python2:

print(u'\xd0\xbf\xd1\x80\xd0\xb8'.encode('raw_unicode_escape'))

Python3:

print(u'\xd0\xbf\xd1\x80\xd0\xb8'.encode('raw_unicode_escape').decode('utf8'))

2
你救了我的一天。我有一个包含UTF-8字节的Unicode对象,需要将其解码回“正常”的Unicode。这个方法对我很有用:my_str.encode('raw_unicode_escape').decode('utf-8')。我认为这是一个比被接受的答案更普遍的解决方案,因为它可以解码不仅在“latin-1”范围内的字符串。谢谢! :) - Ory Band

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接