Найти - Пользователи
Полная версия: Работа со строками
Начало » Python для экспертов » Работа со строками
1 2 3
pablodiguerero
Получаю сообщения с imap сервера, получается вот такая строка:
em =u'\xd0\x9e\xd0\xb1\xd0\xbd\xd0\xbe\xd0\xb2\xd0\xbb\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb5 \xd0\xb0\xd1\x80\xd0\xb5\xd0\xbd\xd0\xb4\xd1\x8b<br><br>\xd0\x9e\xd0\xb1\xd0\xbd\xd0\xbe\xd0\xb2\xd0\xbb\xd0\xb5\xd0\xbd\xd0\xbe \xd0\xbe\xd0\xb1\xd1\x8a\xd0\xb5\xd0\xba\xd1\x82\xd0\xbe\xd0\xb2: 45<br>\xd0\x94\xd0\xb0\xd1\x82\xd0\xb0 \xd0\xbe\xd0\xb1\xd0\xbd\xd0\xbe\xd0\xb2\xd0\xbb\xd0\xb5\xd0\xbd\xd0\xb8\xd1\x8f: 14.05.2013 15:47:02<br><br>=============================================================<br>\xd0\xad\xd1\x82\xd0\xbe \xd0\xbf\xd0\xb8\xd1\x81\xd1\x8c\xd0\xbc\xd0\xbe \xd1\x81\xd0\xb3\xd0\xb5\xd0\xbd\xd0\xb5\xd1\x80\xd0\xb8\xd1\x80\xd0\xbe\xd0\xb2\xd0\xb0\xd0\xbd\xd0\xbe \xd0\xb0\xd0\xb2\xd1\x82\xd0\xbe\xd0\xbc\xd0\xb0\xd1\x82\xd0\xb8\xd1\x87\xd0\xb5\xd1\x81\xd0\xba\xd0\xb8 \xd0\xb8 \xd0\xbe\xd1\x82\xd0\xb2\xd0\xb5\xd1\x82\xd0\xb0 \xd0\xbd\xd0\xb5 \xd1\x82\xd1\x80\xd0\xb5\xd0\xb1\xd1\x83\xd0\xb5\xd1\x82.\r\n'
Получается
Ðбновление аÑендÑ<br><br>Ðбновлено обÑекÑов: 45<br>ÐаÑа обновлениÑ: 14.05.2013 15:47:02<br><br>=============================================================<br>ЭÑо пиÑÑмо ÑгенеÑиÑовано авÑомаÑиÑеÑки и оÑвеÑа не ÑÑебÑеÑ.
Если убрать u перед строкой, то все хорошо. Как можно решить такую проблему?
bismigalis
Если убрать u перед строкой, то все хорошо. Как можно решить такую проблему?
Убрать u перед строкой.
Budulianin
pablodiguerero
Покажи код, где получаешь эту строку.
py.user.next
>>> em = u'\xd0\x9e\xd0\xb1\xd0\xbd\xd0\xbe\xd0\xb2\xd0\xbb\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb5 \xd0\xb0\xd1\x80\xd0\xb5\xd0\xbd\xd0\xb4\xd1\x8b<br><br>\xd0\x9e\xd0\xb1\xd0\xbd\xd0\xbe\xd0\xb2\xd0\xbb\xd0\xb5\xd0\xbd\xd0\xbe \xd0\xbe\xd0\xb1\xd1\x8a\xd0\xb5\xd0\xba\xd1\x82\xd0\xbe\xd0\xb2: 45<br>\xd0\x94\xd0\xb0\xd1\x82\xd0\xb0 \xd0\xbe\xd0\xb1\xd0\xbd\xd0\xbe\xd0\xb2\xd0\xbb\xd0\xb5\xd0\xbd\xd0\xb8\xd1\x8f: 14.05.2013 15:47:02<br><br>=============================================================<br>\xd0\xad\xd1\x82\xd0\xbe \xd0\xbf\xd0\xb8\xd1\x81\xd1\x8c\xd0\xbc\xd0\xbe \xd1\x81\xd0\xb3\xd0\xb5\xd0\xbd\xd0\xb5\xd1\x80\xd0\xb8\xd1\x80\xd0\xbe\xd0\xb2\xd0\xb0\xd0\xbd\xd0\xbe \xd0\xb0\xd0\xb2\xd1\x82\xd0\xbe\xd0\xbc\xd0\xb0\xd1\x82\xd0\xb8\xd1\x87\xd0\xb5\xd1\x81\xd0\xba\xd0\xb8 \xd0\xb8 \xd0\xbe\xd1\x82\xd0\xb2\xd0\xb5\xd1\x82\xd0\xb0 \xd0\xbd\xd0\xb5 \xd1\x82\xd1\x80\xd0\xb5\xd0\xb1\xd1\x83\xd0\xb5\xd1\x82.\r\n'
>>> 
>>> out = em.encode('latin1').decode('utf-8')
>>> print out
Обновление аренды<br><br>Обновлено объектов: 45<br>Дата обновления: 14.05.2013 15:47:02<br><br>=============================================================<br>Это письмо сгенерировано автоматически и ответа не требует.
>>>
Budulianin
py.user.next
Почему Unicode из latin1 так странно выглядит?

>>> 'фывфыв'.decode('latin1')
u'\xd1\x84\xd1\x8b\xd0\xb2\xd1\x84\xd1\x8b\xd0\xb2'
>>> 'фывфыв'.decode('utf-8')
u'\u0444\u044b\u0432\u0444\u044b\u0432'
GreyZmeem
Потому что string - это набор байт.
Если вы попробуете в питоновском шелле написать эту строку на windows и linux, то получите разный результат:
ActivePython 2.7.2.5 (ActiveState Software Inc.) based on Python 2.7.2 (default, Jun 24 2011, 12:21:10) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print 'фыв'.decode('latin1').__repr__()
u'\xe4\xeb\xa2'
>>>
Python 2.7.3 (default, Mar 13 2014, 11:03:55) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print 'фыв'.decode('latin1').__repr__()
u'\xd1\x84\xd1\x8b\xd0\xb2'
>>>

Все дело в том, что python берет кодировку из sys.stdin.encoding, и сохраняет введенный текст как набор байтов используя эту кодировку. В моём случае это было cp866 (на windows), utf-8 (на linux):
>>> print u'фыв'.encode('cp866').__repr__()
'\xe4\xeb\xa2'
>>> print u'фыв'.encode('utf-8').__repr__()
'\xd1\x84\xd1\x8b\xd0\xb2'
>>>

Т.е., когда вы делает:
'фыв'.decode('latin1')
По факту происходит примерно следующие:
Windows:
>>> print sys.stdin.encoding
cp866
>>> u'фыв'.encode(sys.stdin.encoding).decode('latin1')
u'\xe4\xeb\xa2'
>>>
Linux:
>>> print sys.stdin.encoding
UTF-8
>>> u'фыв'.encode(sys.stdin.encoding).decode('latin1')
u'\xd1\x84\xd1\x8b\xd0\xb2'
>>> u'фыв'.encode(sys.stdin.encoding).decode('utf-8')
u'\u0444\u044b\u0432'
>>>

Немного сумбурно, но думаю идея ясна
py.user.next
Во втором питоне:
>>> '\xd1\x84'
'\xd1\x84'
>>> print '\xd1\x84'
ф
>>>

>>> u'\u0444'
u'\u0444'
>>> print u'\u0444'
ф
>>>

Во втором питоне строка - это последовательность байт. Когда делаешь .decode(), метод берёт байты и преобразует их в точки юникода. Как он их преобразует, задаётся в строке кодировки.

latin1 - это однобайтовая кодировка. Он берёт байт и преобразует его в соответствующую кодовую точку.
utf-8 - это кодировка переменной длины. Он набирает валидную последовательность байт и преобразует её в кодовую точку.

Обратное действие:
>>> u'\xd1\x84'.encode('latin1')
'\xd1\x84'
>>>

>>> u'ф'.encode('utf-8')
'\xd1\x84'
>>> u'\u0444'.encode('utf-8')
'\xd1\x84'
>>>

Кодировка latin1 не простая, она полностью совпадает с началом юникода (256 кодовых точек). Поэтому обратное преобразование выглядит как переделывание unicode строки в bytes строку.
Budulianin
GreyZmeem
Потому что string - это набор байт.
Это всем известно.

Вопрос был в другом. Unicode это стандарт, в соответствии с которым, каждому символу определён код типа \u0444. Мне непонятно, почему для latin1 показывает набор байт, а не набор Unicode символов.

py.user.next
Он берёт байт и преобразует его в соответствующую кодовую точку.
Но отображает как набор байтов. В этом вопрос.

py.user.next
Кодировка latin1 не простая
Вижу что непростая.

py.user.next
она полностью совпадает с началом юникода (256 кодовых точек)
Теже самые символы в той же самой последовательности?

py.user.next
Поэтому обратное преобразование выглядит как переделывание unicode строки в bytes строку.
Дак если latin1 перевели в Unicode, он должен быть записан символами Unicode, а не набором байт.
GreyZmeem
Budulianin
Вопрос был в другом. Unicode это стандарт, в соответствии с которым, каждому символу определён код типа \u0444. Мне непонятно, почему для latin1 показывает набор байт, а не набор Unicode символов.
Да, я вас не правильно понял. Вы хотели узнать почему \xd1 не записывает как \u00d1.
Как выше сказал py.user.next, все символы в кодировке latin1 (ISO 8859-1) имеют такой же код в unicode (табличка в вики).
Почему python “экономит байты” - не понятно
Budulianin
>>> print u'\xd1\x8b\xd0\xb2\xd0\xb0\xd1\x84\xd1\x8b\xd0\xb2'
ывафыв
>>> print u'\u00d1\u008b\u00d0\u00b2\u00d0\u00b0\u00d1\u0084\u00d1\u008b\u00d0\u00b2'
ывафыв

Из latin1 вообще принципиально не переводит в символы Unicode.

Кодировка терминала - utf-8
>>> 'xyz'.decode('latin1')
u'xyz'

Кодировка терминала - latin1
>>> 'xyz'.decode('latin1')
u'xyz'
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB