我有一个类似于'%C3%A7%C3%B6asd+fjkls%25asd'
的unicode字符串,我想对它进行解码。
我使用了urllib.unquote_plus(str)
但结果不正确。
- 期望的结果是:
çöasd+fjkls%asd
- 实际得到的结果是:
çöasd fjkls%asd
双重编码的utf-8字符(%C3%A7
和 %C3%B6
)被错误地解码了。
我的python版本是2.7,在Linux发行版上运行。
有什么最好的方法可以得到期望的结果吗?
我有一个类似于'%C3%A7%C3%B6asd+fjkls%25asd'
的unicode字符串,我想对它进行解码。
我使用了urllib.unquote_plus(str)
但结果不正确。
çöasd+fjkls%asd
çöasd fjkls%asd
双重编码的utf-8字符(%C3%A7
和 %C3%B6
)被错误地解码了。
我的python版本是2.7,在Linux发行版上运行。
有什么最好的方法可以得到期望的结果吗?
repr()
和unicodedata.name()
可以帮助你,它们能够明确地展示你所拥有的内容,而不会因控制台编码不同造成混淆。使用print fubar
输出结果时可能会产生这种情况。>>> 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对象转换为字符串对象:
>>> 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'
看前四个字节,它是用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.stdout.encoding进行显式编码的。幸运的是,s3
中的所有unicode字符都可以用该编码(以及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
>>> 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
再试一次urllib2
:
print urllib2.unquote('%C3%A7%C3%B6asd+fjkls%25asd')
%C3%A7%C3%B6asd + fjkls%25asd' - 这不是一个Unicode字符串。
这是一个URL编码的字符串。请使用urllib2.unquote()。
'- user637287print urllib2.unquote('%C3%A7%C3%B6asd+fjkls%25asd')
çöasd+fjkls%asd`我的Python版本是2.7,可能是因为版本差异引起的问题吗?
您正在使用 unquote_plus
方法,该方法会考虑空格并将其转换为 +
。只需使用 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
- user637287print urllib.unquote('%C3%A7%C3%B6asd+fjkls%25asd')
çöasd+fjkls%asd
print urllib.unquote_plus('%C3%A7%C3%B6asd+fjkls%25asd') çöasd fjkls%asd`
s.encode('ascii')
),然后使用 quote_plus
。这样就可以了。 - Senthil Kumaran
import sys; print sys.stdout.encoding
。 - John Machin