我有一个 unicode 字符串'%C3%A7%C3%B6asd+fjkls%25asd'
,我想解码这个字符串。
我用过urllib.unquote_plus(str)
,但效果不对。
- 预期的 :
çöasd+fjkls%asd
- 结果 :
çöasd fjkls%asd
双编码 utf-8 字符(%C3%A7
和%C3%B6
)解码错误。
我的python版本是linux发行版下的2.7。获得预期结果的最佳方法是什么?
我有一个 unicode 字符串'%C3%A7%C3%B6asd+fjkls%25asd'
,我想解码这个字符串。
我用过urllib.unquote_plus(str)
,但效果不对。
çöasd+fjkls%asd
çöasd fjkls%asd
双编码 utf-8 字符(%C3%A7
和%C3%B6
)解码错误。
我的python版本是linux发行版下的2.7。获得预期结果的最佳方法是什么?
你有 3 或 4 或 5 个问题……但repr()
和unicodedata.name()
是你的朋友;它们明确地向您展示了您所拥有的东西,而不会因使用不同控制台编码的人传达print fubar
.
总结:要么(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-波浪号)。让我们暂时搁置这个想法并将其转换为 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 显式编码的。幸运的是,其中的所有 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
您有一个双重问题:您的字符串是 unicode 编码的,并且包含字符 urlencoded。有的搭配。您可以将您的字符串规范化为 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
'%C3%A7%C3%B6asd+fjkls%25asd' - 这不是 unicode 字符串。
这是一个 url 编码的字符串。请改用 urllib2.unquote()。
再试urllib2
一次:
print urllib2.unquote('%C3%A7%C3%B6asd+fjkls%25asd')
您正在使用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