2010-01-27 93 views
20

¿Alguien sabe cómo obtener la codificación de un archivo en Python. Sé que puede usar el módulo de códecs para abrir un archivo con una codificación específica, pero debe saberlo con antelación.¿Cómo saber la codificación de un archivo en Python?

import codecs 
f = codecs.open("file.txt", "r", "utf-8") 

¿Hay alguna forma de detectar automáticamente qué codificación se utiliza para un archivo?

Gracias de antemano

Editar: Gracias a todos por answsers muy interesantes. Usted también puede estar interesado por http://whatismyencoding.com/ que se basa en Chardet (más sobre el sitio es alimentado con biberón marco pitón)

Respuesta

19

Lamentablemente, no hay una forma "correcta" de determinar la codificación de un archivo mirando el archivo. Este es un problema universal, no limitado a Python o cualquier sistema de archivos en particular.

Si está leyendo un archivo XML, la primera línea en el archivo podría darle una pista de lo que es la codificación.

De lo contrario, tendrá que utilizar un enfoque heurístico como chardet (una de las soluciones dadas en otras respuestas) que trata de adivinar la codificación examinando los datos en el archivo en formato de bytes sin formato. Si está en Windows, creo que la API de Windows también expone métodos para tratar de adivinar la codificación en función de los datos del archivo.

3

Hay Unicode Dammit de Beautiful Soup, que usa chardet pero agrega un par de características adicionales.

Intenta leer la codificación desde archivos XML o HTML. Luego intenta buscar una lista de materiales o algo así al comienzo del archivo. Si no puede hacer eso, usa chardet.

3

Aquí hay un pequeño fragmento para ayudarlo a adivinar la codificación. Adivina entre latin1 y utf8 bastante bien. Convierte una cadena de bytes a una cadena Unicode.

# Attention: Order of encoding_guess_list is import. Example: "latin1" always succeeds. 
encoding_guess_list=['utf8', 'latin1'] 
def try_unicode(string, errors='strict'): 
    if isinstance(string, unicode): 
     return string 
    assert isinstance(string, str), repr(string) 
    for enc in encoding_guess_list: 
     try: 
      return string.decode(enc, errors) 
     except UnicodeError, exc: 
      continue 
    raise UnicodeError('Failed to convert %r' % string) 
def test_try_unicode(): 
    for start, should in [ 
     ('\xfc', u'ü'), 
     ('\xc3\xbc', u'ü'), 
     ('\xbb', u'\xbb'), # postgres/psycopg2 latin1: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK 
     ]: 
     result=try_unicode(start, errors='strict') 
     if not result==should: 
      raise Exception(u'Error: start=%r should=%r result=%r' % (
        start, should, result)) 
+0

Gran idea. Gracias. –

+0

Simplifiqué y adapté esto un poco, utilizando simplemente un .decode() en una prueba, excepto que se desencadena después de (1) una conversión exitosa, o (2) después de agotar la encoding_guess_list. Si el final fue un error, entonces aplico un .decode() diferente con los errores establecidos para 'reemplazar' en lugar de 'estricto'. – JDM

1
#!/usr/bin/python 

""" 
Line by line detecting encoding if input and then convert it into UTF-8 
Suitable for look at logs with mixed encoding (i.e. from mail systems) 

""" 

import sys 
import chardet 

while 1: 
     l = sys.stdin.readline() 
     e = chardet.detect(l) 

     u = None 
     try: 
       if e['confidence'] > 0.3: 
         u = unicode(l, e['encoding']) 
     except: 
       pass 

     if u: 
       print u, 
     else: 
       print l, 
Cuestiones relacionadas