2011-02-28 70 views
11

我有一個unicode字符串,如'%C3%A7%C3%B6asd+fjkls%25asd',我想解碼這個字符串。
我使用urllib.unquote_plus(str),但它工作不正確。python url unquote unicode

- expected : 'çöasd+fjkls%asd ' 
- result : 'çöasd fjkls%asd' 

雙重編碼utf-8字符(%C3%A7 and %C3%B6)被解碼錯誤。
我的Python版本是2.7下的Linux發行版
什麼是獲得預期結果的最佳方式?

在此先感謝

+3

請做你的嘗試幫忙一個忙,併發布執行'import sys; print sys.stdout.encoding' –

+0

事實上,解碼本身可能工作正常,但控制檯顯示的重新編碼可能有問題。 – ncoghlan

回答

27

你有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對象:

​​3210

那麼你應該解除引用它:

>>> 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.stdout.encoding顯式編碼。幸運的是,s3中的所有Unicode字符都可用該編碼(以及cp1252和latin1)表示。

+0

我沒有與OP相同的問題,但是編碼和解碼的清晰演練幫助我立即開始了從閱讀相當多文檔中無法獲得的工作。謝謝。 – KobeJohn

0

嘗試urllib2一次:

print urllib2.unquote('%C3%A7%C3%B6asd+fjkls%25asd') 
+0

感謝您的快速回復,我已經嘗試過,它給了我相同的結果。你有其他建議嗎? – user637287

0

'%C3%A7%C3%B6asd + fjkls%25asd' - 這不是一個unicode字符串。

這是一個url編碼的字符串。改用urllib2.unquote()。

+0

這是結果:'>>> import urllib2 >>> print urllib2.unquote('%C3%A7%C3%B6asd + fjkls%25asd') çöasd+ fjkls%asd' my python version是2.7可以是因爲版本差異的問題嗎? – user637287

0

您正在使用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 
+0

實際上,我期望的是第二個輸出,但我做的是完全一樣的東西,這裏是我的結果; '>>> import urllib >>> print urllib.unquote('%C3%A7%C3%B6asd + fjkls%25asd') assasd + fjkls%asd >>> print urllib.unquote_plus(' %C3%A7%C3%B6asd + fjkls%25asd') * asd fjkls%asd' – user637287

+0

將您的字符串編碼爲ascii('s.encode('ascii')'),然後使用quote_plus。它應該做的。 –

0

你有一個雙重問題:你的字符串是unicode編碼的,並且包含calen 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 
+0

我真的認爲我的python版本有問題,因爲我複製了你的代碼,但是結果又是'âöÃÃÃÃÃÃÃÃÃÃ+ fjkls%asd'。即使我已經研究過替代方案,你知道任何其他模塊,我可以使用,而不是urllib – user637287

+0

這個問題不太可能是Python。但說實話,我用完了或理性的解釋:-)你嘗試過巫術嗎?你是否在Python shell中直接嘗試過它?如果不是,您可能需要在其頂部定義文件的編碼。你的操作系統是什麼?我猜窗口,因爲有很多編碼問題。 –

+0

伏都教?有點過時了;嘗試一個手鼓(http://www.elcomsoft.com/tambourine.html?r1=pr&r2=april1)或(更好)'repr()'內置函數。 –

9

無論是使用unquoteunquote_plus會給你一個字節的字符串。如果你想有一個Unicode字符串,那麼你必須字節串爲Unicode解碼:

>>> print(urllib.unquote_plus('%C3%A7%C3%B6asd+fjkls%25asd')) 
çöasd fjkls%asd 
>>> 

請注意,您輸入的字符串必須是一個字節的字符串:

>>> print(urllib.unquote_plus('%C3%A7%C3%B6asd+fjkls%25asd').decode('utf8')) 
çö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 
+0

+ urllib.unquote_plus(u'äö'.encode('ascii'))。decode('utf8')'我需要在Django 1.7中解析一個[文件上傳名稱](https:// docs .djangoproject.com/EN/1.7/REF /文件/上傳/)。 – Larpon

+0

非常有幫助,謝謝。 –