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