Как мне преобразовать юникод в строку на уровне Python? - PullRequest
13 голосов
/ 06 мая 2010

Следующие Unicode и строка могут существовать самостоятельно, если они определены явно:

>>> value_str='Andr\xc3\xa9'
>>> value_uni=u'Andr\xc3\xa9'

Если у меня только u'Andr\xc3\xa9' назначена переменная, как указано выше, как мне преобразовать ее в 'Andr\xc3\xa9' в Python 2.5 или 2.6?

EDIT:

Я сделал следующее:

>>> value_uni.encode('latin-1')
'Andr\xc3\xa9'

которая исправляет мою проблему. Может кто-нибудь объяснить мне, что именно происходит?

Ответы [ 7 ]

13 голосов
/ 06 мая 2010

Вы, кажется, запутали свои кодировки. Кажется вероятным, что вы действительно хотите u'Andr\xe9', что эквивалентно 'André'.

Но то, что у вас есть, похоже на кодировку UTF-8, которая была неправильно декодирована. Вы можете исправить это, преобразовав строку Unicode в обычную строку. Я не уверен, что лучший способ, но это, кажется, работает:

>>> ''.join(chr(ord(c)) for c in u'Andr\xc3\xa9')
'Andr\xc3\xa9'

Затем расшифруйте его правильно:

>>> ''.join(chr(ord(c)) for c in u'Andr\xc3\xa9').decode('utf8')
u'Andr\xe9'    

Теперь это в правильном формате.

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

5 голосов
/ 07 мая 2010

Вы спросили (в комментарии): "" "Это то, что меня озадачивает. Как все вышло с оригинального акцентирования на то, что есть сейчас?(2 utf8 + 1 latin1)? Каков порядок кодирования из исходного состояния в текущее? "" "

В ответе Марка Байерса он говорит:" "кодировка UTF-8, которая была неправильно декодирована "" ".Вы приняли его ответ.Но вы все еще озадачены?Хорошо, вот подробное описание:

Примечание. Все строки будут отображаться с использованием (неявно) repr().unicodedata.name() будет использоваться для проверки содержимого.Таким образом, изменения в кодировке консоли не могут запутать интерпретацию строк.

Исходное состояние: у вас есть объект Unicode, который вы назвали u1.Он содержит e-sharp:

>>> u1 = u'\xe9'
>>> import unicodedata as ucd
>>> ucd.name(u1)
'LATIN SMALL LETTER E WITH ACUTE'

Вы кодируете u1 как UTF-8 и называете результат s:

>>> s = u1.encode('utf8')
>>> s
'\xc3\xa9'

Вы декодируете s, используя latin1 - НЕПРАВИЛЬНО;s был закодирован с использованием utf8, а не latin1.Результат - бессмысленный мусор.

>>> u2 = s.decode('latin1')
>>> u2
u'\xc3\xa9'
>>> ucd.name(u2[0]); ucd.name(u2[1])
'LATIN CAPITAL LETTER A WITH TILDE'
'COPYRIGHT SIGN'
>>>

Пожалуйста, поймите: unicode_object.encode('x').decode('y), когда x! = Y обычно [см. Примечание ниже], глупость;это вызовет исключение, если вам повезет;если вам не повезет, это тихо создаст бред.Также, пожалуйста, поймите, что тихое создание тарабарщины не является ошибкой - нет общего способа, которым Python (или любой другой язык) может обнаружить, что ерунда была совершена.Это особенно применимо, когда задействован latin1, потому что все 256 кодовых точек отображаются с 1 на 1 с первыми 256 кодовыми точками Unicode, поэтому невозможно получить UnicodeDecodeError из str_object.decode ('latin1').

Конечно,ненормально (можно надеяться, что оно ненормально), вам, возможно, придется обратить вспять такую ​​ерунду, выполнив gibberish_unicode_object.encode('y').decode('x'), как предлагается в различных ответах на ваш вопрос.

4 голосов
/ 06 мая 2010

value_uni.encode('utf8') или любую необходимую вам кодировку.

См. http://docs.python.org/library/stdtypes.html#str.encode

1 голос
/ 07 мая 2010

Если у вас есть u'Andr\xc3\xa9', это строка Unicode, которая была декодирована из байтовой строки с неправильной кодировкой. Правильная кодировка UTF-8. Чтобы преобразовать его обратно в строку байтов, чтобы вы могли правильно его декодировать, вы можете использовать обнаруженный трюк. Первые 256 кодовых точек Unicode представляют собой отображение 1: 1 с кодировкой ISO-8859-1 (псевдоним latin1). Итак:

>>> u'Andr\xc3\xa9'.encode('latin1')
'Andr\xc3\xa9'

Теперь это строка байтов, которую можно правильно декодировать с помощью utf8:

>>> 'Andr\xc3\xa9'.decode('utf8')
u'Andr\xe9'
>>> print 'Andr\xc3\xa9'.decode('utf8')
André

За один шаг:

>>> print u'Andr\xc3\xa9'.encode('latin1').decode('utf8')
André
1 голос
/ 06 мая 2010

ОП не конвертируется ни в ascii, ни в utf-8. Вот почему предложенные encode методы не будут работать. Попробуйте это:

v = u'Andr\xc3\xa9'
s = ''.join(map(lambda x: chr(ord(x)),v))

Бизнес chr(ord(x)) получает числовое значение символа Unicode (которое лучше подходит для одного байта для вашего приложения), а вызов ''.join - это идиома, которая преобразует список целых чисел обратно в обычную строку. Без сомнения, есть более элегантный способ.

0 голосов
/ 06 мая 2010

Упрощенное объяснение. Тип str может содержать только символы в диапазоне 0-255. Если вы хотите сохранить Unicode (который может содержать символы из гораздо более широкого диапазона) в str, вы сначала должны закодировать Unicode в формат, подходящий для str, например UTF-8.

Для этого метода вызова необходимо кодировать объект str и в качестве аргумента указать требуемую кодировку, например, this_is_str = value_uni.encode('utf-8').

Вы можете прочитать более подробную и углубленную (и не зависящую от языка) статью об обработке Unicode здесь: Абсолютный минимум, который должен знать каждый разработчик программного обеспечения Об Unicode и наборах символов (без извинений!) .

Еще одна отличная статья (на этот раз для Python): Unicode HOWTO

0 голосов
/ 06 мая 2010

Вроде как

str(value_uni)

должно работать ... по крайней мере, так оно и было, когда я попробовал.

РЕДАКТИРОВАТЬ : Оказывается, это работает только потому, что код моей системы по умолчанию, насколько я могу судить, ISO-8859-1 (Latin-1) Так что для независимой от платформы версии попробуйте

value_uni.encode('latin1')
...