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

я использовал мутаген для преобразования данных из ID3-тегов CP-1251/CP-1252 в UTF-8. В Linux нет проблем. Но на Windows, назвав SetValue() на wx.TextCtrl выдает ошибку:

UnicodeDecodeError: кодек 'ascii' не может декодировать байт 0xc3 в позиции 0: порядковый номер не в диапазон(128)

исходная строка (предполагается, что она закодирована CP-1251), которую я вытягиваю из мутаген есть:

u'xc1xe5xebxe0xff xffxe1xebxfbxedxff xe3xf0xeexecxf3'

Я попытался преобразовать это в UTF-8:

dd = d.decode('utf-8')

...и даже изменение кодировки по умолчанию с ASCII на UTF-8:

sys.setdefaultencoding('utf-8')

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

6 ответов


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

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

строка d является строкой Юникода,не строка в кодировке 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 является правильной строкой Unicode, затем d.encode('utf-8') дает закодированный UTF-8 bytestring. Не тестируйте его печатью, хотя, возможно, он просто не отображается должным образом из-за махинаций с кодовыми страницами.


Я предоставил некоторую соответствующую информацию о кодировании / декодировании текста в этом ответе:https://stackoverflow.com/a/34662963/2957811

чтобы добавить к этому здесь, важно думать о тексте в одном из двух возможных состояний: "закодировано" и "декодировано"

'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.....'

это неверное представление данных в юникоде. Итак, Тим Pietzcker прав. Сначала вы должны кодировать() , затем декодировать() , а затем кодируйте снова, чтобы исправить кодировку.

поэтому в моем случае эта странная строка была сохранена в переменной" text", а строка:

print text.encode("cp1251").decode('cp1251').encode('utf8')   

Я:

"Своя 2-х комнатная квартира с отличным ремонтом...."

Да, это тоже сводит меня с ума. Но это работает!

П. С. сохранение в файл, вы должны сделать точно так же.

some_file.write(text.encode("cp1251").decode('cp1251').encode('utf8'))

Я бы предпочел добавить комментарий к Александр Степаненко ответ, но моя репутация не позволит. У меня была аналогичная проблема преобразования тегов MP3 из CP-1251 в UTF-8, и решение encode/decode/encode работало для меня. За исключением того, что мне пришлось заменить первую кодировку на "latin-1", которая по существу преобразует строку Unicode в байтовую последовательность без реальной кодировки:

print text.encode("latin-1").decode('cp1251').encode('utf8')

и для сохранения назад, используя, например, мутаген, его не нужно кодировать:

audio["title"] = title.encode("latin-1").decode('cp1251')