2011-02-28 19 views
11

tengo una cadena Unicode como '%C3%A7%C3%B6asd+fjkls%25asd' y quiero decodificar esta cadena.
He usado urllib.unquote_plus (str) pero funciona mal.python url unquit unicode

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

dobles codificados caracteres UTF-8 (%C3%A7 and %C3%B6) se decodifican mal.
mi versión de python es 2.7 bajo una distribución de Linux
¿cuál es la mejor manera de obtener el resultado esperado?

gracias de antemano

+3

Por favor haga un favor a sus ayudantes y publique el resultado de ejecutar 'import sys; print sys.stdout.encoding' –

+0

De hecho, es probable que la descodificación funcione correctamente, pero la reencoding para la pantalla de la consola puede estar teniendo problemas. – ncoghlan

Respuesta

27

tiene 3 o 4 o 5 problemas ... pero repr() y unicodedata.name() son sus amigos; sin ambigüedades le muestran exactamente lo que tiene, sin la confusión engendrada por personas con diferentes codificaciones de consola que comunican los resultados de print fubar.

Resumen: bien (a) empiezas con un objeto Unicode y aplicas la función de comillas a eso o (b) comienzas con un objeto str y tu consola de codificación no es UTF-8.

Si como usted dice usted comienza con un objeto Unicode:

>>> s0 = u'%C3%A7%C3%B6asd+fjkls%25asd' 
>>> print repr(s0) 
u'%C3%A7%C3%B6asd+fjkls%25asd' 

esto es un disparate accidental. Si aplica urllibX.unquote_YYYY(), obtendrá otro objeto Unicode sin sentido (u'\xc3\xa7\xc3\xb6asd+fjkls%asd') que causaría los síntomas que se muestran cuando se imprima.Debe convertir el objeto Unicode original a un objeto str inmediato:

>>> s1 = s0.encode('ascii') 
>>> print repr(s1) 
'%C3%A7%C3%B6asd+fjkls%25asd' 

entonces debería fin de la cita que:

>>> import urllib2 
>>> s2 = urllib2.unquote(s1) 
>>> print repr(s2) 
'\xc3\xa7\xc3\xb6asd+fjkls%asd' 

En cuanto a los primeros 4 bytes de eso, se codifica en UTF-8. Si lo hace print s2, se verá bien si su consola está esperando UTF-8, pero si está esperando ISO-8859-1 (también conocido como latin1) verá la basura sintomática (el primer carácter será A-tilde). Vamos parque que pensó por un momento y convertirlo en un objeto Unicode:

>>> s3 = s2.decode('utf8') 
>>> print repr(s3) 
u'\xe7\xf6asd+fjkls%asd' 

e inspeccionar para ver lo que realmente tenemos:

>>> 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 

Parece que lo que ha dicho que esperaba. Ahora llegamos a la pregunta de mostrarlo en su consola. Nota: no se asuste cuando vea "cp850"; Estoy haciendo esto de manera portátil y estoy haciendo esto en un Símbolo del sistema en Windows.

>>> import sys 
>>> sys.stdout.encoding 
'cp850' 
>>> print s3 
çöasd+fjkls%asd 

Nota: el objeto Unicode se codificó explícitamente mediante sys.stdout.encoding. Afortunadamente, todos los caracteres Unicode en s3 son representables en esa codificación (y cp1252 y latin1).

+0

No tuve el mismo problema que OP, pero su clara guía de codificación y decodificación me ayudó a ponerme inmediatamente a trabajar lo que no pude leer después de leer un poco de documentación. Gracias. – KobeJohn

0

Trate urllib2 una vez más:

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

gracias por su rápida respuesta, ya lo probé y me dio el mismo resultado. Tienes alguna otra sugerencia ? – user637287

0

'% C3% A7% C3% B6asd + fjkls% 25asd' - esto no es una cadena Unicode.

Esto es una cadena codificada en url. Use urllib2.unquote() en su lugar.

+0

estos son los resultados: '>>> import urllib2 >>> print urllib2.unquote ('% C3% A7% C3% B6asd + fjkls% 25asd') çöasd + fjkls% asd' my python version ¿2.7 puede ser el problema debido a las diferencias de versión? – user637287

0

Está utilizando el método unquote_plus que está tomando en cuenta space y convirtiendo a +. Solo use el método unquote y debería estar bien.

>>> 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

en realidad, lo que esperaba es la segunda salida, pero estoy haciendo exactamente lo mismo y aquí están mis resultados; '>>> 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' – user637287

+0

Codificando su cadena a ascii ('s.encode (' ascii ')') y luego usando quote_plus. Debería hacer –

0

Tiene un doble problema: la cadena tiene codificación Unicode y contiene el carácter urlencoded. Algunos coinciden. Puede normalizar su cadena a ascci para asegurarse de que no va a ser interpretado de forma incorrecta:

>>> 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

realmente creo que algo anda mal con mi versión de Python porque copié tu código pero el resultado fue 'çöasd + fjkls% asd' de nuevo. a pesar de que ya he investigado alternativas, ¿conoces algún otro módulo que pueda usar en lugar de urllib – user637287

+0

? El problema es poco probable que sea Python. Pero para ser sincero, me estoy quedando sin explicaciones racionales :-) ¿Has probado el vudú? ¿Lo has probado directamente en el shell de Python? Si no, es posible que desee definir la codificación de su archivo en la parte superior. ¿Cuál es tu sistema operativo? Supongo que Windows tiene muchos problemas de codificación. –

+0

vudú? un poco anticuado; pruebe una pandereta (http://www.elcomsoft.com/tambourine.html?r1=pr&r2=april1) o (mucho mejor) la función incorporada 'repr()'. –

9

Utilizando cualquiera unquote o unquote_plus le dará una serie de bytes. Si quieres una cadena Unicode entonces usted tiene que decodificar la cadena de bytes de Unicode:

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

En comparación con:

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

Tenga en cuenta que la cadena de entrada debe ser una cadena de bytes: si pasa Unicode para unquote/unquote_plus, entonces te encontrarás un poco desordenado. Si este es el caso, entonces codificarlo primero:

>>> print(urllib.unquote_plus(u'%C3%A7%C3%B6asd+fjkls%25asd'.encode('ascii')).decode('utf8')) 
çöasd fjkls%asd 
+0

+1 para 'urllib.unquote_plus (u'äö'.encode ('ascii')). Decode ('utf8')' Lo necesitaba en Django 1.7 para decodificar un [nombre de carga de archivo] (https: // docs .djangoproject.com/es/1.7/ref/files/uploads /). – Larpon

+0

Muy útil, gracias. –