Уведомления

Группа в Telegram: @pythonsu

#1 Авг. 27, 2013 01:26:03

skavans
Зарегистрирован: 2012-11-13
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

utf8-escaped в unicode-строке

Возникла странная проблема: есть файл в формате JSON, в нем, в одном из полей есть URL, который содержит кириллицу в виде search?q=%D1%81%D0%B0%D1%85%D0%B0%D0%BB%D0%B8%D0%BD.
Далее с помощью json.load() создаю dict из него, делаю urllib.unquote() и получаю вот такой объект u'\xd0\xbb\xd0\xbe\xd1\x82\xd1\x8b\xd0\xb2\xd0\xbb\xd0\xbe\xd0\xb0\xd1\x82'.
Если честно, не могу сказать, что на все 100% понял, как работать с кодировками и encode/decode, но судя по всему, это неправильный объект - utf-escaped строка лежит в unicode-строке..
В связи с этим, прошу помощи в 2 вопросах:
1) как из этого объекта получить нормальную читаемую строку;
2) в чем вообще причина такой ошибки.

Спасибо за ответы.

Офлайн

#2 Авг. 27, 2013 01:59:23

4kpt
От: Харьков
Зарегистрирован: 2010-11-03
Сообщения: 998
Репутация: +  63  -
Профиль   Отправить e-mail  

utf8-escaped в unicode-строке

Первое. Где Вы видите ошибку?

Второе. Получить ожидаемые данные:

# coding: utf-8
import quopri
str_ = "%D1%81%D0%B0%D1%85%D0%B0%D0%BB%D0%B8%D0%BD".replace("%", "=")
res = quopri.decodestring(str_).decode("utf-8")
print res

Третье. Это вопрос не для экспертов :)



Отредактировано 4kpt (Авг. 27, 2013 02:06:31)

Офлайн

#3 Авг. 27, 2013 03:41:37

wbt
Зарегистрирован: 2013-08-13
Сообщения: 143
Репутация: +  6  -
Профиль   Отправить e-mail  

utf8-escaped в unicode-строке

\x - это не уникоды, уникоды - \u

>>> a = '\xd0\xbb\xd0\xbe\xd1\x82\xd1\x8b\xd0\xb2\xd0\xbb\xd0\xbe\xd0\xb0\xd1\x82'
>>> a
'\xd0\xbb\xd0\xbe\xd1\x82\xd1\x8b\xd0\xb2\xd0\xbb\xd0\xbe\xd0\xb0\xd1\x82'
>>> len(a)
18
>>> type(a)
<type 'str'>
>>> unicode(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 0: ordinal not in range(128)
>>> a = a.decode('utf-8')
>>> a
u'\u043b\u043e\u0442\u044b\u0432\u043b\u043e\u0430\u0442'
>>> len(a)
9
>>> type(a)
<type 'unicode'>



Бейсик - не порок, Гвидо - не пророк

Офлайн

#4 Авг. 27, 2013 09:48:00

skavans
Зарегистрирован: 2012-11-13
Сообщения: 33
Репутация: +  0  -
Профиль   Отправить e-mail  

utf8-escaped в unicode-строке

Насколько я понимаю, ошибка в литере u перед строкой. То есть правильными объектами являются
“\xd0\xbb” или u“\u043b”, а у меня получается u“\xd0\xbb”. То есть байтовое представление символов лежит в Unicode-строке, где должно быть символьное представление. В результате, если сделать print такого объекта, печатаются кракозябры прошу прощения, если недостаточно понятно объяснил в первом посте.
В процессе гугления нашел ответ на похожую проблему: “уберите литеру u перед строкой, потому что это не Unicode, а UTF8”. Но как ее убрать - вот в чем вопрос

Офлайн

#5 Авг. 27, 2013 10:08:44

wbt
Зарегистрирован: 2013-08-13
Сообщения: 143
Репутация: +  6  -
Профиль   Отправить e-mail  

utf8-escaped в unicode-строке

А вот это уже интересно:

>>> a
u'\xd0\xbb\xd0\xbe\xd1\x82\xd1\x8b\xd0\xb2\xd0\xbb\xd0\xbe\xd0\xb0\xd1\x82'
>>> a.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-17: ordinal not in range(128)
>>> str(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-17: ordinal not in range(128)
>>> bytes(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-17: ordinal not in range(128)
>>> a[0]
u'\xd0'
>>> type(a)
<type 'unicode'>
>>> repr(a)
"u'\\xd0\\xbb\\xd0\\xbe\\xd1\\x82\\xd1\\x8b\\xd0\\xb2\\xd0\\xbb\\xd0\\xbe\\xd0\\xb0\\xd1\\x82'"

python даёт ввести данные, которые заведомо неверны, но не даёт ничего из них получить, потому что они заведомо неверны. как просто поменять тип, не трогая данные - я так и не нашёл.

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



Бейсик - не порок, Гвидо - не пророк

Офлайн

#6 Авг. 27, 2013 10:12:30

wbt
Зарегистрирован: 2013-08-13
Сообщения: 143
Репутация: +  6  -
Профиль   Отправить e-mail  

utf8-escaped в unicode-строке

что-то типа такого:

>>> a.encode('latin1')
'\xd0\xbb\xd0\xbe\xd1\x82\xd1\x8b\xd0\xb2\xd0\xbb\xd0\xbe\xd0\xb0\xd1\x82'
>>> a.encode('latin1').decode('utf-8')
u'\u043b\u043e\u0442\u044b\u0432\u043b\u043e\u0430\u0442'
>>> print a.encode('latin1').decode('utf-8')
лотывлоат



Бейсик - не порок, Гвидо - не пророк

Офлайн

#7 Авг. 27, 2013 10:24:20

4kpt
От: Харьков
Зарегистрирован: 2010-11-03
Сообщения: 998
Репутация: +  63  -
Профиль   Отправить e-mail  

utf8-escaped в unicode-строке

wbt
лотывлоат
Мощно.

Должно получиться по исходной кодировке :)

сахалин



Отредактировано 4kpt (Авг. 27, 2013 10:24:58)

Офлайн

#8 Авг. 27, 2013 10:36:22

wbt
Зарегистрирован: 2013-08-13
Сообщения: 143
Репутация: +  6  -
Профиль   Отправить e-mail  

utf8-escaped в unicode-строке

>>> import urllib
>>> a = urllib.unquote('%D1%81%D0%B0%D1%85%D0%B0%D0%BB%D0%B8%D0%BD')
>>> a
'\xd1\x81\xd0\xb0\xd1\x85\xd0\xb0\xd0\xbb\xd0\xb8\xd0\xbd'
>>> print a.decode('utf-8')
сахалин

каким образом из
'\xd0\xbb\xd0\xbe\xd1\x82\xd1\x8b\xd0\xb2\xd0\xbb\xd0\xbe\xd0\xb0\xd1\x82'
можно получить “сахалин”, если там даже число букв явно разное? если бы это был невалидный utf-8, были бы тоже кракозяблы, наверное, а не текст.



Бейсик - не порок, Гвидо - не пророк

Офлайн

#9 Авг. 27, 2013 11:00:35

4kpt
От: Харьков
Зарегистрирован: 2010-11-03
Сообщения: 998
Репутация: +  63  -
Профиль   Отправить e-mail  

utf8-escaped в unicode-строке

:)

Как Вы тогда объясните это:

http://coding-cs.ru/%d0%ba%d0%be%d0%bd%d1%82%d0%b0%d0%ba%d1%82%d1%8b/

Переходим и видим

http://coding-cs.ru/контакты/

Написанный код также выдает:

# coding: utf-8
import quopri
str_ = "%d0%ba%d0%be%d0%bd%d1%82%d0%b0%d0%ba%d1%82%d1%8b".replace("%","=")
res = quopri.decodestring(str_).decode("utf-8")
print res

контакты

P.S. Гляньте сюда http://ru.wikipedia.org/wiki/URL
Раздел “Кодирование URL”.



Отредактировано 4kpt (Авг. 27, 2013 11:05:14)

Офлайн

#10 Авг. 27, 2013 11:10:16

wbt
Зарегистрирован: 2013-08-13
Сообщения: 143
Репутация: +  6  -
Профиль   Отправить e-mail  

utf8-escaped в unicode-строке

print '\xd0\xba\xd0\xbe\xd0\xbd\xd1\x82\xd0\xb0\xd0\xba\xd1\x82\xd1\x8b'.decode('utf-8')
контакты

в utf-8, если байт начинается от C0 до DF, то используется 2 байта.

в строке ‘xd0\xbb\xd0\xbe\xd1\x82\xd1\x8b\xd0\xb2\xd0\xbb\xd0\xbe\xd0\xb0\xd1\x82’ все байты начинаются только с D0 или D1. следовательно, здесь 9 символов. в utf-8. сахалин в 9 символов не попадает никак.

если это не utf-8, то вероятность того, что эти символы попали бы на русские буквы, да ещё и у всех были бы одинаковые стартовые биты - примерно равна 0, а может и ровно 0, и таких вариантов просто не может быть.

Так что, дело очень просто, Ватсон - в строке xd0\xbb\xd0\xbe\xd1\x82\xd1\x8b\xd0\xb2\xd0\xbb\xd0\xbe\xd0\xb0\xd1\x82 закодировано лотывлоат, что бы это не значило.



Бейсик - не порок, Гвидо - не пророк

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version