0

我有 unicode 列表

lst = [u'\xd0\xbe', u'/', u'\xd0\xb8', u'\xd1\x81', u'\xd0\xb2', u'\xd0\xba', u'\xd1\x8f', u'\xd1\x83', u'\xd0\xbd\xd0\xb0', u'____', u'|', u'\xd0\xbf\xd0\xbe', u'11', u'search', u'\xd0\xbe\xd1\x82', u'**modis**', u'15', u'\xd0\xa1', u'**avito**', u'\xd0\xbd\xd0\xb5', u'[\xd0\xa1\xd0\xbe\xd1\x85\xd1\x80\xd0\xb0\xd0\xbd\xd1\x91\xd0\xbd\xd0\xbd\xd0\xb0\xd1\x8f', u'\xd0\x92', u'\xd0\xb5\xd1\x89\xd1\x91', u'kid', u'google', u'\xd0\xbb\xd0\xb8', u'13', u'**\xd0\xb0\xd0\xb2\xd0\xb8\xd1\x82\xd0\xbe**', u'[\xd0\x9f\xd0\xbe\xd0\xba\xd0\xb0\xd0\xb7\xd0\xb0\xd1\x82\xd1\x8c', u'\xd0\x9f\xd0\xbe\xd0\xb6\xd0\xb0\xd0\xbb\xd0\xbe\xd0\xb2\xd0\xb0\xd1\x82\xd1\x8c\xd1\x81\xd1\x8f', u'\xd0\x9e', u'&parent-', u'\xd0\xaf\xd0\xbd\xd0\xb4\xd0\xb5\xd0\xba\xd1\x81', u'###', u'**avito**.', u'**kiddieland**', u'\xd0\xbc\xd0\xb0\xd0\xb3\xd0\xb0\xd0\xb7\xd0\xb8\xd0\xbd', u'45', u'click2.yandex.ru/redir', u'72']

我尝试将一些喜欢转换u'\xd0\xbe'为俄语。我尝试使用 2 和 3 python,但我不能这样做。我使用 IDE Pycharm,在设置中我有默认的 utf-8。当我用

for elem in lst:
    print (elem)

它返回我о的第一个元素。当我尝试print (elem.encode('cp1252')) 它返回b'\xd0\xbe' 当我使用chardet.detect它返回我时,它是utf-8. 任何人都可以向我解释,我怎样才能将它转换为俄语字母以及为什么我使用的方法不适合得到它。

4

2 回答 2

1

您的列表中的元素似乎是以 UTF-8 编码的字节字符串,但它们是类型str(或unicode在 Python 2 中)。

我使用以下内容将它们转换回正确的 UTF-8:

def reinterpret(string):
    byte_arr = bytearray(ord(char) for char in string)
    return byte_arr.decode('utf8')

这给出了以下内容,看起来更像俄语:

>>> for elem in lst:
...     print(reinterpret(elem))
... 
о
/
и
с
в
к
я
у
на
____
|
по
11
search
от
**modis**
15
С
**avito**
не
[Сохранённая
В
ещё
kid
google
ли
13
**авито**
[Показать
Пожаловаться
О
&parent-
Яндекс
###
**avito**.
**kiddieland**
магазин
45
click2.yandex.ru/redir
72
于 2016-10-12T15:54:04.250 回答
1

您的数据是Mojibake,从 UTF-8 字节错误地解码为 Latin-1 或 CP1252。

您可以通过手动还原该过程来修复此问题:

repaired = [elem.encode('latin1').decode('utf8') for elem in lst]

但小心点; 如果数据实际上被解码为 cp1252,那么如果源数据中有 0x80-0x9f 范围内的任何字节,上述操作将失败。

您可以改用该ftfy;它包含也可以处理强制解码的专业编解码器(其中字节被选择性地解码为 Latin-1,其中缺少 CP1252 映射):

import ftfy

repaired = [ftfy.fix_text(elem) for elem in lst]

ftfy.fix_text()在自动检测数据解码时使用的编解码器方面做得很好。

任何一种方法都适用于您提供的样本数据;使用ftfy或手动解码对该特定示例没有影响:

>>> import ftfy
>>> repaired = [ftfy.fix_text(elem) for elem in lst]
>>> repaired
[u'\u043e', u'/', u'\u0438', u'\u0441', u'\u0432', u'\u043a', u'\u044f', u'\u0443', u'\u043d\u0430', u'____', u'|', u'\u043f\u043e', u'11', u'search', u'\u043e\u0442', u'**modis**', u'15', u'\u0421', u'**avito**', u'\u043d\u0435', u'[\u0421\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u0430\u044f', u'\u0412', u'\u0435\u0449\u0451', u'kid', u'google', u'\u043b\u0438', u'13', u'**\u0430\u0432\u0438\u0442\u043e**', u'[\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c', u'\u041f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c\u0441\u044f', u'\u041e', u'&parent-', u'\u042f\u043d\u0434\u0435\u043a\u0441', u'###', u'**avito**.', u'**kiddieland**', u'\u043c\u0430\u0433\u0430\u0437\u0438\u043d', u'45', u'click2.yandex.ru/redir', u'72']
>>> print repaired[20]
[Сохранённая

当然,更好的解决方案是首先避免创建 Mojibake。如果你能纠正错误的根源,那就更好了。

例如,如果您使用requests库加载此数据并假设使用该response.text属性是安全的,那么请阅读库文档中高级用法一章的编码部分:

只有在 HTTP 标头中不存在显式字符集且 Content-Type 标头包含文本时,Requests 才会这样做。在这种情况下,RFC 2616 指定默认字符集必须是 ISO-8859-1。在这种情况下,请求遵循规范。如果你需要不同的编码,你可以手动设置Response.encoding属性,或者使用 raw Response.content

因此,如果响应中定义了字符集,response.text则会改为为您提供 Latin-1 解码文本。在这种情况下最好避免使用response.text和使用response.content,而是手动解码或使用适合格式的解析器来确定使用的编解码器(例如 HTML 的 BeautifulSoup)。

于 2016-10-12T15:54:05.400 回答