Ответ 1
Если вы точно знаете, что у вас есть cp1251 на вашем входе, вы можете сделать
d.decode('cp1251').encode('utf8')
Я использую mutagen для преобразования данных тегов ID3 из CP-1251/CP-1252 до UTF-8. В Linux проблем нет. Но в Windows при вызове SetValue()
на wx.TextCtrl возникает ошибка:
UnicodeDecodeError: кодек 'ascii' не может декодировать байт 0xc3 в позиции 0: порядковый не в диапазоне (128)
Исходная строка (предположительно закодированная CP-1251), которую я вытягиваю из mutagen:
u'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'
Я попытался преобразовать это в UTF-8:
dd = d.decode('utf-8')
... и даже изменение кодировки по умолчанию от ASCII до UTF-8:
sys.setdefaultencoding('utf-8')
... Но я получаю ту же ошибку.
Если вы точно знаете, что у вас есть cp1251 на вашем входе, вы можете сделать
d.decode('cp1251').encode('utf8')
Ваша строка d
является строкой Unicode, а не строкой в кодировке UTF-8! Таким образом, вы не можете decode()
его, вы должны encode()
его использовать для UTF-8 или любого необходимого вам кодирования.
>>> d = u'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'
>>> d
u'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'
>>> print d
Áåëàÿ ÿáëûíÿ ãðîìó
>>> a.encode("utf-8")
'\xc3\x81\xc3\xa5\xc3\xab\xc3\xa0\xc3\xbf \xc3\xbf\xc3\xa1\xc3\xab\xc3\xbb\xc3\xad\xc3\xbf \xc3\xa3\xc3\xb0\xc3\xae\xc3\xac\xc3\xb3'
(это то, что вы делали бы в самом конце всей обработки, если вам нужно сохранить его как файл с кодировкой UTF-8, например).
Если ваш вход находится в другом кодировании, это наоборот:
>>> d = "Schoßhündchen" # native encoding: cp850
>>> d = "Schoßhündchen".decode("cp850") # decode from Windows codepage
>>> d # into a Unicode string (now work with this!)
u'Scho\xdfh\xfcndchen'
>>> print d # it displays correctly if your shell knows the glyphs
Schoßhündchen
>>> d.encode("utf-8") # before output, convert to UTF-8
'Scho\xc3\x9fh\xc3\xbcndchen'
Если d
- правильная строка Юникода, то d.encode('utf-8')
дает кодированную UTF-8. Не проверяйте его путем печати, хотя может быть, что он просто не отображается должным образом из-за кодовых страниц. Шеняниганы.
В этом ответе я привел некоторую релевантную информацию о тексте кодирования/декодирования: fooobar.com/questions/322688/...
Чтобы добавить к этому здесь, важно подумать о тексте в одном из двух возможных состояний: "закодировано" и "декодировано"
'decoded' означает, что он находится во внутреннем представлении вашим интерпретатором/библиотеками, которые могут использоваться для манипулирования символами (например, поиск, преобразование регистров, нарезка подстроки, количество символов,...) или отображение (поиск кодовой точки в шрифте и рисовании глифа), но не может быть передан или запущен в процессе работы.
'encoded' означает, что это байтовый поток, который можно передавать, как и любые другие данные, но не полезен для манипуляции или отображения.
Если вы раньше работали с сериализованными объектами, рассмотрите "декодированный" как полезный объект в памяти и "закодированный" для сериализованной версии.
'\xc1\xe5\xeb\xe0\xff \xff\xe1\xeb\xfb\xed\xff \xe3\xf0\xee\xec\xf3'
- ваша кодированная (или сериализованная) версия, предположительно закодированная cp1251. Эта кодировка должна быть правильной, потому что "язык" используется для сериализации символов и необходим для воссоздания символов в памяти.
Вы нуждаетесь, чтобы декодировать это из текущей кодировки (cp1251) в символы юникода python, а затем перекодировать его как поток байтов utf8. Ответчик, который предложил d.decode('cp1251').encode('utf8')
, имел это право, я просто надеюсь помочь объяснить, почему это должно работать.
Я потерял половину своего дня, чтобы найти правильный ответ. Так что если вы получили строку unicode из внешнего источника windows-1251, закодированного (с веб-сайта в моей ситуации), вы увидите в консоли Linux что-то вроде этого:
u '\ u043a\u043e\u043c\u043d\u0430\u0442\u043d\u0430\u044f\u043a\u0432\u0430\u0440\u0442\u0438\u0440\u0430.....'
Это неправильная презентация ваших данных в формате unicode. Итак, Тим Пицкер прав. Вы должны сначала закодировать(), затем декодировать(), а затем снова закодировать, чтобы исправить кодировку.
Итак, в моем случае эта странная строка была сохранена в "текстовой" переменной, а строка:
print text.encode("cp1251").decode('cp1251').encode('utf8')
дал мне:
"Своя 2-х комнатная квартира с отличным ремонтом...."
Да, это тоже сходит с ума. Но это работает!
P.S. Сохраняя файл, вы должны сделать то же самое.
some_file.write(text.encode("cp1251").decode('cp1251').encode('utf8'))
Я бы предпочел добавить комментарий к Александру Степаненко, но моя репутация пока не позволяет. У меня была аналогичная проблема с конвертированием тэгов MP3 из CP-1251 в UTF-8, и решение для кодирования/декодирования/кодирования работало для меня. За исключением того, что мне пришлось заменить первую кодировку на "latin-1", которая по существу преобразует строку Unicode в байтовую последовательность без реальной кодировки:
print text.encode("latin-1").decode('cp1251').encode('utf8')
и для сохранения обратно с использованием, например, мутагена, его не нужно кодировать:
audio["title"] = title.encode("latin-1").decode('cp1251')