2010-06-14 6 views
3

J'ai créé un script qui effectue une recherche et un remplacement à grande échelle sur un document en texte brut. À l'heure actuelle, il fonctionne très bien avec ASCII, UTF-8 et UTF-16 (et éventuellement d'autres, mais j'ai seulement testé ces trois documents) tant que l'encodage est spécifié dans le script (l'exemple le code ci-dessous spécifie UTF-16).Définir un script pour détecter automatiquement l'encodage des caractères dans un fichier texte en Python?

Est-il possible de faire en sorte que le script détecte automatiquement lequel de ces codages de caractères est utilisé dans le fichier d'entrée et définit automatiquement le codage de caractères du fichier de sortie comme le codage utilisé dans le fichier d'entrée?

findreplace = [ 
('term1', 'term2'), 
]  

inF = open(infile,'rb') 
    s=unicode(inF.read(),'utf-16') 
    inF.close() 

    for couple in findreplace: 
     outtext=s.replace(couple[0],couple[1]) 
     s=outtext 

    outF = open(outFile,'wb') 
    outF.write(outtext.encode('utf-16')) 
    outF.close() 

Merci!

+0

liés « Python et travailler avec encodages » http://stackoverflow.com/questions/819310/python-and-working-with-encodings – jfs

Répondre

3

Du lien J.F. Sebastian posté: essayez chardet.

Gardez à l'esprit que, en général, il est impossible de détecter le codage de caractères de chaque fichier d'entrée 100% fiable - en d'autres termes, il y a des fichiers d'entrée possibles qui pourraient être interprétées aussi bien que l'un des plusieurs codages de caractères, et il peut y avoir aucun moyen de dire lequel est réellement utilisé. chardet utilise des méthodes heuristiques et vous donne un niveau de confiance indiquant à quel point il est "sûr" que le caractère qui le code vous est correct.

1

Non, il n'y en a pas. Vous devez encoder cette connaissance dans le fichier lui-même ou à partir d'une source externe.

Il y a quelques heuristiques, qui peut deviner l'encodage d'un fichier par l'analyse statistique de la fréquence de l'ordre des octets; mais je ne les utiliserai pas pour des données critiques.

3

Quelques observations et questions:

(1) ASCII est un sous-ensemble de UTF-8 dans le sens que si un fichier peut être décodé avec succès en ASCII, alors il peut être décodé avec succès en utilisant UTF-8. Vous pouvez donc sortir l'ASCII de votre liste. (2) Les deux termes de findreplace vont-ils jamais inclure des caractères non-ASCII? Notez qu'une réponse de "oui" indiquerait que l'objectif d'écrire un fichier de sortie dans le même jeu de caractères que l'entrée peut être difficile/impossible à réaliser.

(3) Pourquoi ne pas écrire TOUS les fichiers de sortie dans l'encodage SAME handle-all-Unicode-characters, par ex. UTF-8?

(4) Les fichiers UTF-8 ont-ils une nomenclature?

(5) Quels autres jeux de caractères prévoyez-vous gérer? (6) Laquelle des quatre possibilités (UTF-16LE/UTF-16BE) x (BOM/no BOM) appelez-vous UTF-16? Notez que je ne cherche délibérément pas à déduire quoi que ce soit de la présence de 'utf-16' dans votre code.

(7) Notez que chardet ne détecte pas UTF-16xE sans nomenclature. chardet a d'autres angles morts avec des jeux de caractères non * x et plus anciens.

Mise à jour Voici quelques extraits de code que vous pouvez utiliser pour déterminer ce qu'est «ANSI» et essayer de décoder en utilisant une liste restreinte de codages. Remarque: cela suppose un environnement Windows.

# determine "ANSI" 
import locale 
ansi = locale.getdefaultlocale()[1] # produces 'cp1252' on my Windows box. 

f = open("input_file_path", "rb") 
data = f.read() 
f.close() 

if data.startswith("\xEF\xBB\xBF"): # UTF-8 "BOM" 
    encodings = ["utf-8-sig"] 
elif data.startswith(("\xFF\xFE", "\xFE\xFF")): # UTF-16 BOMs 
    encodings = ["utf16"] 
else: 
    encodings = ["utf8", ansi, "utf-16le"] 
# ascii is a subset of both "ANSI" and "UTF-8", so you don't need it. 
# ISO-8859-1 aka latin1 defines all 256 bytes as valid codepoints; so it will 
# decode ANYTHING; so if you feel that you must include it, put it LAST. 
# It is possible that a utf-16le file may be decoded without exception 
# by the "ansi" codec, and vice versa. 
# Checking that your input text makes sense, always a very good idea, is very 
# important when you are guessing encodings. 

for enc in encodings: 
    try: 
     udata = data.decode(enc) 
     break 
    except UnicodeDecodeError: 
     pass 
else: 
    raise Exception("unknown encoding") 

# udata is your file contents as a unicode object 
# When writing the output file, use 'utf8-sig' as the encoding if you 
# want a BOM at the start. 
+0

Désolé, je suis un peu d'un débutant à tout cela! Comme vous le suggérez dans 3, je l'ai changé maintenant pour qu'il sorte toujours en UTF-8. Comme les gens qui utiliseraient cela utilisent des machines Windows, j'imagine que les fichiers UTF-8 auraient une nomenclature. Je prévois de distribuer le script parmi les non-technophiles, donc il faut simplement accepter les différents jeux de caractères par défaut, rien de spécial. Donc en réponse à 5, il faudrait probablement ANSI, ASCII, UTF8, UTF16 et ISO 8859-1. –

+0

@Haidon: Veuillez répondre aux questions Q2 et Q6. Lorsqu'on vous demande des éclaircissements, éditez votre question au lieu de commenter. Qu'est-ce qui vous fait penser que ISO-8859-1 est un "jeu de caractères par défaut sur Windows"? Comment l'utilisateur moyen de Windows créerait-il un tel fichier? –

+0

@detly: Merci; fixé. –

Questions connexes