Python: очистить строку для Unicode?
Возможный дубликат:
Python UnicodeDecodeError - Я неправильно понимаю кодирование?
У меня есть строка, которую я пытаюсь сделать безопасным для unicode()
функция:
>>> s = " foo “bar bar ” weasel"
>>> s.encode('utf-8', 'ignore')
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
s.encode('utf-8', 'ignore')
UnicodeDecodeError: 'ascii' codec can't decode byte 0x93 in position 5: ordinal not in range(128)
>>> unicode(s)
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
unicode(s)
UnicodeDecodeError: 'ascii' codec can't decode byte 0x93 in position 5: ordinal not in range(128)
Я в основном трясусь здесь. Что мне нужно сделать, чтобы удалить небезопасные символы из строки?
Несколько связано с этим вопросом, хотя я не смог решить свою проблему из него.
Это также не удается:
>>> s
' foo \x93bar bar \x94 weasel'
>>> s.decode('utf-8')
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
s.decode('utf-8')
File "C:\Python25\254\lib\encodings\utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x93 in position 5: unexpected code byte
2 ответа
Хороший вопрос. Проблемы с кодированием сложны. Давайте начнем с "У меня есть строка". Строки в Python 2 на самом деле не являются "строками", это байтовые массивы. Итак, ваша строка, откуда она взялась и в какой кодировке? Ваш пример показывает фигурные кавычки в буквальном, и я даже не уверен, как вы это сделали. Я пытаюсь вставить его в интерпретатор Python или набрать его в OS X с помощью Option-[, но ничего не получается.
Однако, глядя на ваш второй пример, у вас есть символ с шестнадцатеричным значением 93. Это не может быть UTF-8, потому что в UTF-8 любой байт, превышающий 127, является частью многобайтовой последовательности. Я предполагаю, что это будет Latin-1. Проблема в том, что x 93 не является символом в наборе символов Latin-1. В Latin-1 есть этот "недопустимый" диапазон от x7f до x9f, который считается незаконным. Однако Microsoft увидела этот неиспользованный диапазон и решила поместить туда "фигурные цитаты". При этом они создали подобную кодировку под названием "windows-1252", которая похожа на Latin-1 с содержимым в этом недопустимом диапазоне.
Итак, давайте предположим, что это Windows-1252. Что теперь? String.decode конвертирует байты в Unicode, так что это именно то, что вам нужно. Ваш второй пример был на правильном пути, но он не удался, потому что строка не была UTF-8. Пытаться:
>>> uni = 'foo \x93bar bar\x94 weasel'.decode("windows-1252")
u'foo \u201cbar bar\u201d weasel'
>>> print uni
foo “bar bar” weasel
>>> type(uni)
<type 'unicode'>
Это правильно, потому что открывающая фигурная кавычка - это Unicode U+201C. Теперь, когда у вас есть Unicode, вы можете сериализовать его в байты в любой выбранной вами кодировке (если вам нужно передать ее по проводам) или просто сохранить как Unicode, если он находится в Python. Если вы хотите конвертировать в UTF-8, используйте противоположную функцию string.encode.
>>> uni.encode("utf-8")
'foo \xe2\x80\x9cbar bar \xe2\x80\x9d weasel'
Фигурные кавычки занимают 3 байта для кодирования в UTF-8. Вы можете использовать UTF-16, и они будут только два байта. Вы не можете кодировать как ASCII или Latin-1, потому что у них нет фигурных кавычек.
РЕДАКТИРОВАТЬ. Похоже, ваша строка закодирована таким образом, что “
(СЛЕДУЮЩАЯ ДВОЙНАЯ МАРКА ЦИТАТЫ) становится \x93
а также ”
(ПРАВИЛЬНАЯ ДВОЙНАЯ ЦИТАТА) \x94
, Существует несколько кодовых страниц с таким отображением, CP1250 - одна из них, поэтому вы можете использовать это:
s = s.decode('cp1250')
Для всех кодовых страниц, которые отображаются “
в \x93
смотрите здесь (все они также карта ”
в \x94
, что можно проверить здесь).