python url unquote с последующим декодированием unicode
у меня есть строка unicode, как '%C3%A7%C3%B6asd+fjkls%25asd'
и я хочу декодировать эту строку.
Я использовал urllib.unquote_plus(str)
но оно работает неправильно.
- ожидается :
çöasd+fjkls%asd
- результат :
çöasd fjkls%asd
двойной код utf-8 символов (%C3%A7
и %C3%B6
) декодируются неправильно.
Моя версия python-2.7 под дистрибутивом linux.
Каков наилучший способ получить ожидаемый результат?
6 ответов
у вас есть 3 или 4 или 5 задач ... но!--6--> и unicodedata.name()
ваши друзья; они однозначно показывают вам именно то, что у вас есть, без путаницы, порожденной людьми с различными консольными кодировками, сообщающими результаты print fubar
.
Summary: либо (a) вы начинаете с объекта unicode и применяете к нему функцию unquote, либо (b) вы начинаете с объекта str, и ваша консольная кодировка не является UTF-8.
если, как вы говорите, вы начинаете с объектом unicode:
>>> s0 = u'%C3%A7%C3%B6asd+fjkls%25asd'
>>> print repr(s0)
u'%C3%A7%C3%B6asd+fjkls%25asd'
это случайная бессмыслица. Если вы применяете urllibX.unquote_YYYY()
к нему вы получаете еще один бессмысленный объект unicode (u'\xc3\xa7\xc3\xb6asd+fjkls%asd'
) что вызвало бы ваши показанные симптомы при печати. Вы должны немедленно преобразовать исходный объект unicode в объект str:
>>> s1 = s0.encode('ascii')
>>> print repr(s1)
'%C3%A7%C3%B6asd+fjkls%25asd'
тогда вы должны отменить кавычки:
>>> import urllib2
>>> s2 = urllib2.unquote(s1)
>>> print repr(s2)
'\xc3\xa7\xc3\xb6asd+fjkls%asd'
глядя на первые 4 байта этого, он закодирован в UTF-8. Если вы это сделаете print s2
, это будет выглядеть нормально, если ваша консоль ожидая UTF-8, но если он ожидает ISO-8859-1 (он же latin1), вы увидите свой симптоматический мусор (первый символ будет a-tilde). Давайте припаркуем эту мысль на мгновение и преобразуем ее в объект Unicode:
>>> s3 = s2.decode('utf8')
>>> print repr(s3)
u'\xe7\xf6asd+fjkls%asd'
и осмотрите его, чтобы увидеть, что у нас есть:
>>> import unicodedata
>>> for c in s3[:6]:
... print repr(c), unicodedata.name(c)
...
u'\xe7' LATIN SMALL LETTER C WITH CEDILLA
u'\xf6' LATIN SMALL LETTER O WITH DIAERESIS
u'a' LATIN SMALL LETTER A
u's' LATIN SMALL LETTER S
u'd' LATIN SMALL LETTER D
u'+' PLUS SIGN
похоже, что вы сказали, что ожидали. Теперь мы подошли к вопросу отображения на консоли. Примечание: не волнуйтесь, когда вы видите "cp850"; я делаю это переносимо и просто так получилось это делается в командной строке в Windows.
>>> import sys
>>> sys.stdout.encoding
'cp850'
>>> print s3
çöasd+fjkls%asd
Примечание: объект unicode был явно закодирован с помощью sys.стандартный вывод.кодирование. К счастью, все символы Unicode в s3
представимы в этой кодировке (и cp1252 и latin1).
используя unquote
или unquote_plus
даст вам строку байта. Если вам нужна строка Unicode, вам нужно декодировать строку байтов в unicode:
>>> print(urllib.unquote_plus('%C3%A7%C3%B6asd+fjkls%25asd').decode('utf8'))
çöasd fjkls%asd
>>>
по сравнению с:
>>> print(urllib.unquote_plus('%C3%A7%C3%B6asd+fjkls%25asd'))
çöasd fjkls%asd
>>>
обратите внимание, что входная строка должна быть строкой байта: если вы передаете unicode в unquote/unquote_plus
тогда вы получите немного беспорядок. Если это так, то сначала Закодируйте его:
>>> print(urllib.unquote_plus(u'%C3%A7%C3%B6asd+fjkls%25asd'.encode('ascii')).decode('utf8'))
çöasd fjkls%asd
'%C3%A7%C3%B6asd+fjkls%25asd' - это не строка Юникода.
это строка в кодировке url. Использовать urllib2.вместо этого unquote ().
у вас есть двойная проблема: ваша строка кодируется в юникоде и содержит urlencoded caracter. Некоторые матчи. Вы можете нормализовать строку в ascci, чтобы убедиться, что она не будет интерпретирована неправильно:
>>> s = '%C3%A7%C3%B6asd+fjkls%25asd' # ascii string
>>> print urllib2.unquote(s) # works as expected
çöasd+fjkls%asd
>>> s = u'%C3%A7%C3%B6asd+fjkls%25asd' # unicode string
>>> print urllib2.unquote(s) # decode stuff that it shouldn't
çöasd+fjkls%asd
>>> print urllib2.unquote(s.encode('ascii')) # encode the unicode string to ascii: works!
çöasd+fjkls%asd
вы используете unquote_plus
метод, который принимает space
учитывать и преобразовывать в +
. Просто используйте unquote
метод, и вы должны быть в порядке.
>>> import urllib
>>> print urllib.unquote('%C3%A7%C3%B6asd+fjkls%25asd')
çöasd+fjkls%asd
>>> print urllib.unquote_plus('%C3%A7%C3%B6asd+fjkls%25asd')
çöasd fjkls%asd