URL: https://linuxfr.org/users/lovasoa/journaux/toutf8-autodetecter-et-convertir-de-n-importe-quel-encodage-de-caracteres-vers-utf8 Title: toutf8: autodétecter et convertir de n'importe quel encodage de caractères vers UTF8 Authors: lovasoa Date: 2015年11月23日T17:27:08+01:00 License: CC By-SA Tags: ubuntu, encodage, unicode, transcodage, utf8 et debian Score: 42 Les fichiers textes encodés avec des codecs exotiques, c'est toujours énervant. Il existe des tonnes et des tonnes normes d'encodage de caractères différentes, parfois partiellement compatibles entre elles, qui font qu'ouvrir un fichier texte est parfois une galère. Personnellement, j'ai souvent le problème avec des sous-titres de films en français où en russes, qui ne sont jamais dans le même encodage de caractère, et dont il faut à chaque fois deviner l'encodage, avant de le convertir. Pour résoudre ce problème, il existe déjà certains outils... # Les outils ## uchardet [uchardet](https://github.com/BYVoid/uchardet), développé par mozilla pour son navigateur, permet de détecter l'encodage du fichier. Il est codé en C++ et se fonde sur une méthode statistique pour détecter l'encodage de caractères: il connaît la fréquence des lettres dans différentes langues, et l'encodage de ces lettres dans différents codecs, et s'en sert pour deviner l'encodage de caractères. Il est disponible dans les dépôts debian et ubuntu sous le nom uchardet: sudo apt install uchardet ## iconv [iconv](https://en.wikipedia.org/wiki/Iconv) est un outil permettant de transcoder un fichier d'un encodage de caractère à un autre (par défaut, il transcode vers l'UTF8). Il sort le fichier décodé sur la sortie standart, et s'utilise ainsi: ```bash iconv -f INPUT-ENCODING -t OUTPUT-ENCODING input-file.txt> output-file.txt ``` ## recode recode fait la même chose qu'iconv, mais écrase le fichier d'entrée. C'est dangereux, mais parfois pratique. À n'utiliser que si l'on est sûr de l'encodage d'entrée. ```bash recode INPUT-ENCODING file-to-transcode.txt ``` ## Comment combiner ces outils Le plus simple pour utiliser ces outils ensembles, en bash: ```bash recode $(uchardet fichier.txt) fichier.txt ``` # Et si ça ne marche pas Et voilà, on en arrive enfin à la raison pour laquelle j'ai écrit ce journal. uchardet utilise une méthode statistiques fondée sur la fréquence des lettres. C'est bien, parce que c'est rapide, et que ce n'est pas gros. Mais l'inconvénient, c'est qu'il lui arrive de se tromper, entre deux codecs proches et deux langues proches, quand le fichier comprend peu de caractères spéciaux. Donc j'ai écrit un petit script python, qui se fonde sur l'utilsation d'un dictionnaire pour détecter la langue du fichier. L'inconvénient, c'est que c'est beaucoup plus lent: 1.5 secondes pour un fichier de sous-titres d'un film d'1h30 (~100Kio). Le script est tout petit, donc je me permets de le poster ici. Il est aussi disponible sur github: [toutf8](https://github.com/lovasoa/toutf8/tree/master). ```python #!/usr/bin/env python3 #coding: utf8 import encodings import re import sys if len(sys.argv) is 1: filein,fileout = ("/dev/stdin", "/dev/stdout") elif len(sys.argv) is 2: filein,fileout = (sys.argv[1], sys.argv[1]) else : filein,fileout = (sys.argv[1], sys.argv[2]) with open(filein, "rb") as f: buf = f.read() wordlists = tuple(map(lambda f:set(map(str.strip, open(f,"r"))), ("/usr/share/dict/russian", "/usr/share/dict/french", "/usr/share/dict/american-english"))) scores = dict() tok = re.compile("\w+") codings = set(encodings.aliases.aliases.values()) for i,encoding in enumerate(codings): try: txt = encodings.codecs.decode(buf, encoding) except: continue if type(txt) is not str: continue found_words = (sum(m.group(0) in wl for m in tok.finditer(txt)) for wl in wordlists) scores[encoding] = max(found_words) codec = max(scores.keys(), key=lambda k:scores[k]) with open(fileout, "w") as f: f.write(encodings.codecs.decode(buf, codec)) ```