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

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

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

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

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

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

6 ответов

Решение

Если вы точно знаете, что у вас есть вход 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. Не проверяйте это, печатая, хотя, возможно, это просто не отображается должным образом из-за shenanigans кодовой страницы.

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

Я потерял половину дня, чтобы найти правильный ответ. Так что если вы получили какую-то строку юникода из внешнего источника в кодировке windows-1251 (с веб-сайта в моей ситуации), вы увидите в консоли Linux что-то вроде этого:

u 'u043a \ u043c \ u043d \ u0442 \ u043d \ u044f \ u043a \ u0432 \ u0430 \ u0440 \ u0442 \ u0438 \ u0440 \ u0430.....'

Это неверное представление ваших данных в Юникоде. Итак, Тим Пицкер прав. Вы должны кодировать () сначала его, затем декодировать (), а затем кодировать снова, чтобы исправить кодировку.

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

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

дал мне:

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

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

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

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

Я предоставил некоторую соответствующую информацию о кодировании / декодировании текста в этом ответе: /questions/9287607/vyivesti-stroku-v-kodirovke-yunikod-v-konsol-ok-no-proishodit-sboj-pri-perenapravlenii-v-fajl-kak-ispravit/9287621#9287621

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

"декодированный" означает, что он находится во внутреннем представлении вашего интерпретатора / библиотеки, который может использоваться для манипулирования символами (например, поиска, преобразования регистра, нарезки подстроки, подсчета символов,...) или отображения (поиска кодовой точки в шрифте). и рисование глифа), но не может быть передано в или из запущенного процесса.

"закодированный" означает, что это поток байтов, который может передаваться так же, как и любые другие данные, но бесполезен для манипулирования или отображения.

Если вы раньше работали с сериализованными объектами, считайте "декодированный" полезным объектом в памяти, а "закодированный" - сериализованной версией.

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

Другие вопросы по тегам