2010-10-04 10 views
8

Quiero que mi función tome un argumento que podría ser un objeto unicode o una cadena codificada en utf-8. Dentro de mi función, quiero convertir el argumento a Unicode. Tengo algo como esto:Decodificación si no es unicode

def myfunction(text): 
    if not isinstance(text, unicode): 
     text = unicode(text, 'utf-8') 

    ... 

¿Es posible evitar el uso de isinstance? Estaba buscando algo más amigable para escribir patos.

Durante mis experimentos con decodificación, he encontrado varios comportamientos raros de Python. Por ejemplo:

>>> u'hello'.decode('utf-8') 
u'hello' 
>>> u'cer\xf3n'.decode('utf-8') 
Traceback (most recent call last): 
    File "<input>", line 1, in <module> 
    File "/usr/lib/python2.6/encodings/utf_8.py", line 16, in decode 
    return codecs.utf_8_decode(input, errors, True) 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf3' in po 
sition 3: ordinal not in range(128) 

O

>>> u'hello'.decode('utf-8') 
u'hello' 12:11 
>>> unicode(u'hello', 'utf-8') 
Traceback (most recent call last): 
File "<input>", line 1, in <module> 
TypeError: decoding Unicode is not supported 

Por cierto. Estoy usando Python 2.6

+0

es posible que desee echar un vistazo a esta pregunta: [UnicodeDecodeError Python - ¿Estoy entendiendo mal Unicode?] (http://stackoverflow.com/questions/368805/) – tzot

Respuesta

14

se podía intentar decodificar con el códec 'UTF-8', y si eso no funciona, entonces devolver el objeto.

def myfunction(text): 
    try: 
     text = unicode(text, 'utf-8') 
    except TypeError: 
     return text 

print(myfunction(u'cer\xf3n')) 
# cerón 

Cuando se toma un objeto Unicode y llama a su método decode con el códec 'utf-8', Python primero intenta convertir el objeto Unicode a un objeto de cadena, y entonces se llama decodificación del objeto de cadena ('UTF-8') método.

A veces la conversión del objeto Unicode al objeto de cadena falla porque Python2 usa el códec asci por defecto.

Por lo tanto, en general, nunca intente descodificar objetos Unicode. O, si debe intentar, atraparlo en un intento ... excepto bloque. Puede haber unos pocos códecs para los cuales la decodificación de objetos Unicode funciona en Python2 (ver a continuación), pero se han eliminado en Python3.

Ver este Python bug ticket para una interesante discusión sobre el tema, y también Guido van Rossum's blog:

"Estamos adoptando una enfoque ligeramente diferente a los codecs: mientras que en Python 2, códecs pueden aceptar Unicode o 8 bits como entrada y producir ya sea como de salida, en Py3k, la codificación es siempre una traducción de un Unicode (texto) cadena en una matriz de bytes, y decodificación siempre va lo contrario dirección. Esto significa que tuvimos que caer algunas códecs que no encajan en este modelo, por ejemplo, rot13 base64 y bz2 (esas conversiones son todavía compatibles, pero no a través de la API envío/recepción) ".

0

No conozco ninguna buena manera de evitar el control isinstance en su función, pero tal vez alguien más lo haga. Puedo señalar que las dos peculiaridades que cita son porque está haciendo algo que no tiene sentido: intentar decodificar en Unicode algo que ya está decodificado en Unicode.

El primer lugar debería tener este aspecto, que decodifica la codificación UTF-8 de esa cadena en la versión Unicode:

>>> 'cer\xc3\xb3n'.decode('utf-8') 
u'cer\xf3n' 

Y el segundo debe tener este aspecto (sin utilizar una cadena de u'' Unicode literal) :

>>> unicode('hello', 'utf-8') 
u'hello' 
+0

La reflexión es raro que los objetos Unicode tienen una método de decodificación. Aún más extraño es que el método funciona a veces y a veces no. Lo mismo para llamadas de unicode(). –

+0

Bueno, definitivamente hay cierta extrañeza en la API, desde una llamada a 'unicode' con una cadena Unicode yn o la codificación especificada siempre funcionará, mientras que una llamada con cualquier codificación especificada siempre fallará. –

Cuestiones relacionadas