Подтвердить что ты не робот

Как преобразовать строку из CP-1251 в UTF-8?

Я использую 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')

... Но я получаю ту же ошибку.

4b9b3361

Ответ 1

Если вы точно знаете, что у вас есть cp1251 на вашем входе, вы можете сделать

d.decode('cp1251').encode('utf8')

Ответ 2

Ваша строка 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'

Ответ 3

Если d - правильная строка Юникода, то d.encode('utf-8') дает кодированную UTF-8. Не проверяйте его путем печати, хотя может быть, что он просто не отображается должным образом из-за кодовых страниц. Шеняниганы.

Ответ 4

В этом ответе я привел некоторую релевантную информацию о тексте кодирования/декодирования: 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'), имел это право, я просто надеюсь помочь объяснить, почему это должно работать.

Ответ 5

Я потерял половину своего дня, чтобы найти правильный ответ. Так что если вы получили строку 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'))

Ответ 6

Я бы предпочел добавить комментарий к Александру Степаненко, но моя репутация пока не позволяет. У меня была аналогичная проблема с конвертированием тэгов 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')