2008-11-06 18 views
15

Escribo software de procesamiento de correo en Python que encuentra bytes extraños en los campos del encabezado. Sospecho que esto es solo correo mal formado; el mensaje mismo dice ser nosotros-ascii, así que no creo que haya una codificación verdadera, pero me gustaría obtener una cadena unicode que se aproxime a la original sin tirar un UnicodeDecodeError.¿Hay una función de biblioteca de Python que intente adivinar la codificación de caracteres de algunos bytes?

Por lo tanto, estoy buscando una función que lleva un str y, opcionalmente, algunos consejos y hace su más pena devolverme un unicode. Podría escribir uno por supuesto, pero si tal función existe, probablemente su autor haya pensado un poco más sobre la mejor manera de hacerlo.

También sé que el diseño de Python prefiere explícito a implícito y que la biblioteca estándar está diseñada para evitar la magia implícita en la decodificación de texto. Solo quiero decir explícitamente "adelante y adivine".

Respuesta

12

Por lo que yo sé, la biblioteca estándar no tiene una función, aunque no es demasiado difícil escribir una como se sugirió anteriormente. Creo que lo real que estaba buscando era una forma de decodificar una cadena y garantizar que no arrojaría una excepción. El parámetro de errores para string.decode hace eso.

def decode(s, encodings=('ascii', 'utf8', 'latin1')): 
    for encoding in encodings: 
     try: 
      return s.decode(encoding) 
     except UnicodeDecodeError: 
      pass 
    return s.decode('ascii', 'ignore') 
+1

Puede omitir el caso '' ascii'' al final y simplemente usar 'latin1', ya que' latin1' decodificará todos los valores de 256 bytes sin error. –

20

Usted podría estar interesado en Universal Encoding Detector.

+0

+1 por ser 5 segundos más rápido que yo :-) –

+0

Muy útil, gracias. Pero no en la biblioteca estándar. – Nick

18

+1 para el módulo chardet (sugerido por @insin).

no está en la biblioteca estándar, pero se puede instalar fácilmente con el comando siguiente:

$ pip install chardet 

Example:

>>> import chardet 
>>> import urllib 
>>> detect = lambda url: chardet.detect(urllib.urlopen(url).read()) 
>>> detect('http://stackoverflow.com') 
{'confidence': 0.85663169917190185, 'encoding': 'ISO-8859-2'}  
>>> detect('https://stackoverflow.com/questions/269060/is-there-a-python-lib') 
{'confidence': 0.98999999999999999, 'encoding': 'utf-8'} 

Ver Installing Pip si no tiene uno.

+1

¿No te pareció que 'ISO-8859-2' era una tontería? –

+0

@John Machin: Sí, lo era. Es educativo mostrar que no debes confiar ciegamente en eso. Los resultados actuales son diferentes ('utf-8' y 'ascii' correspondientemente). – jfs

1

La mejor manera de hacer esto que he encontrado es iterativamente intentar decodificar un prospecto con cada una de las codificaciones más comunes dentro de un bloque de prueba excepto.

Cuestiones relacionadas