2009-11-11 18 views
6

¿Lo he conseguido todo correctamente? De todos modos, estoy analizando una gran cantidad de html, pero no siempre sé qué codificación tiene que ser (un sorprendente número miente al respecto). El siguiente código muestra fácilmente lo que he estado haciendo hasta ahora, pero estoy seguro de que hay una mejor manera. Tus sugerencias serán muy apreciadas.La mejor manera de descodificar la codificación de unicodificación desconocida en Python 2.5

import logging 
import codecs 
from utils.error import Error 

class UnicodingError(Error): 
    pass 

# these encodings should be in most likely order to save time 
encodings = [ "ascii", "utf_8", "big5", "big5hkscs", "cp037", "cp424", "cp437", "cp500", "cp737", "cp775", "cp850", "cp852", "cp855", 
    "cp856", "cp857", "cp860", "cp861", "cp862", "cp863", "cp864", "cp865", "cp866", "cp869", "cp874", "cp875", "cp932", "cp949", 
    "cp950", "cp1006", "cp1026", "cp1140", "cp1250", "cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256", "cp1257", "cp1258", 
    "euc_jp", "euc_jis_2004", "euc_jisx0213", "euc_kr", "gb2312", "gbk", "gb18030", "hz", "iso2022_jp", "iso2022_jp_1", "iso2022_jp_2", 
    "iso2022_jp_2004", "iso2022_jp_3", "iso2022_jp_ext", "iso2022_kr", "latin_1", "iso8859_2", "iso8859_3", "iso8859_4", "iso8859_5", 
    "iso8859_6", "iso8859_7", "iso8859_8", "iso8859_9", "iso8859_10", "iso8859_13", "iso8859_14", "iso8859_15", "johab", "koi8_r", "koi8_u", 
    "mac_cyrillic", "mac_greek", "mac_iceland", "mac_latin2", "mac_roman", "mac_turkish", "ptcp154", "shift_jis", "shift_jis_2004", 
    "shift_jisx0213", "utf_32", "utf_32_be", "utf_32_le", "utf_16", "utf_16_be", "utf_16_le", "utf_7", "utf_8_sig" ] 

def unicode(string): 
    '''make unicode''' 
    for enc in self.encodings: 
     try: 
      logging.debug("unicoder is trying " + enc + " encoding") 
      utf8 = unicode(string, enc) 
      logging.info("unicoder is using " + enc + " encoding") 
      return utf8 
     except UnicodingError: 
      if enc == self.encodings[-1]: 
       raise UnicodingError("still don't recognise encoding after trying do guess.") 
+0

La detección automática no sabe * absolutamente nada * sobre su texto, pero si conoce al menos el idioma en el que está el texto, existen muy pocas opciones. Es por eso que la detección de codificación básicamente significa intentar adivinar el idioma según la frecuencia de las letras. –

+0

Erm, unicode() devuelve Unicode y no UTF-8. –

Respuesta

8

Hay dos bibliotecas de uso general para la detección de códigos desconocidos:

Chardet se supone que es un puerto de la way that firefox does it

Puede usar la siguiente expresión regular para detectar utf8 de la cadena de bytes s:

import re 

utf8_detector = re.compile(r"""^(?: 
    [\x09\x0A\x0D\x20-\x7E]   # ASCII 
    | [\xC2-\xDF][\x80-\xBF]    # non-overlong 2-byte 
    | \xE0[\xA0-\xBF][\x80-\xBF]  # excluding overlongs 
    | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte 
    | \xED[\x80-\x9F][\x80-\xBF]  # excluding surrogates 
    | \xF0[\x90-\xBF][\x80-\xBF]{2}  # planes 1-3 
    | [\xF1-\xF3][\x80-\xBF]{3}   # planes 4-15 
    | \xF4[\x80-\x8F][\x80-\xBF]{2}  # plane 16 
)*$""", re.X) 

En la práctica, si usted está tratando con Inglés que he encontrado las siguientes obras 99,9% del tiempo:

  1. si pasa por encima de la expresión regular, que es ASCII o UTF-8
  2. si contiene bytes de 0x80-0x9f pero no 0xa4, es de Windows-1252
  3. si contiene 0xa4, asumir que es latino-15
  4. lo contrario asumir que es latino-1
+1

He codificado esto y lo puse aquí http: // pastebin.com/f76609aec – user132262

+0

Existe un problema con el código que pegó: '^ (?: \ xA4) * $' coincidirá si la cadena es * completamente * '\ xA4' y no tiene otros caracteres. Solo necesita 're.compile (r '\ xA4')' y 're.compile (r '[\ x80- \ xBF]')' para las otras dos expresiones regulares. –

1

dado que está utilizando Python, puede intentar UnicodeDammit. Es parte de Beautiful Soup que también puede serle útil.

Como su nombre indica, UnicodeDammit intentará hacer lo que sea necesario para obtener un unicode adecuado de la basura que pueda encontrar en el mundo.

+0

Intenté eso desde el principio, pero falló bastante. – user132262

+0

¡De verdad! ¿Cuáles fueron los problemas? Puede ser más fácil hacer que funcione el propio. –

+0

"¿La basura que puedes encontrar en el mundo"? – Sabuncu

2

He resuelto el mismo problema y he descubierto que no hay forma de determinar el tipo de codificación del contenido sin metadatos sobre el contenido. Es por eso que terminé con el mismo enfoque que estás intentando aquí.

Mi único consejo adicional sobre lo que has hecho es que, en lugar de ordenar la lista de posibles codificaciones en el orden más probable, debes encargarla por especificidad. Descubrí que ciertos juegos de caracteres son subconjuntos de otros, por lo que si selecciona utf_8 como su segunda opción, perderá la oportunidad de encontrar los subconjuntos de utf_8 (creo que uno de los juegos de caracteres coreanos usa el mismo espacio de números que utf)

+0

De hecho. 'ascii' es un subconjunto de' utf-8' y también decodificará correctamente como 'utf-8', por lo que puede dejar' ascii'. Las codificaciones de 8 bits, como 'latin-1', se decodificarán a _something_ en todos los casos, así que ponga una de estas últimas. – Thomas

Cuestiones relacionadas