Python:将一些编码转换为俄语字母

时间:2016-10-12 15:29:16

标签: python unicode encoding utf-8 mojibake

我有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。 任何人都可以向我解释,如何将其转换为俄语字母,以及为什么我使用的方法并不适合它。

2 个答案:

答案 0 :(得分:1)

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

我使用以下内容将它们转换回正确的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

答案 1 :(得分:1)

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

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

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

但要小心;如果数据实际上被解码为cp1252,如果源数据中的0x80-0x9f范围内有任何字节,则上述情况会失败。

您可以使用ftfy library代替;它包含可以处理强制解码的专业编解码器(其中字节被选择性地解码为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属性是安全的,那么请阅读Encodings section库文档中的高级用法章节:

  

请求不会执行此操作的唯一情况是,如果HTTP标头中不存在显式字符集,并且Content-Type标头包含文本。在这种情况下,RFC 2616指定默认字符集必须是ISO-8859-1。在这种情况下,请求遵循规范。如果您需要不同的编码,可以手动设置Response.encoding属性,或使用原始Response.content

因此,如果在响应中定义了字符集,response.text将为您提供Latin-1解码文本。在这种情况下,最好避免使用response.text并使用response.content,并手动解码或使用格式相关的解析器来确定所使用的编解码器(例如用于HTML的BeatifulSoup)。