convertir encodage python

Convertir à la volée l’encodage des fichiers avec Python

Il y a encore quelques années, j’étais un petit con qui écrivait ses codes en ISO… Cela me suffisait. Mais voilà! Entre temps, j’ai été contaminé par le virus UTF-8. Alors du coup, quand il m’arrive de reprendre de très vieux fichiers, il faut que je les convertisse en UTF-8. Et quand il y a tout un répertoire, autant dire que je n’ai pas du tout envie de m’y coller manuellement.

Conversion de l’encodage d’un fichier: première approche

Je suis tombé un jour sur un code, sans doute trop vieux, qui est à mes yeux assez long… et qui ne fonctionne pas chez moi:

def typecode(dossier,fichier): # détermine l'encodage du fichier
    d = os.path.join(dossier, fichier)
    fich = open(d,'rb')
    contenu=fich.read()
    fich.close()
    codage=chardet.detect(contenu)['encoding']
    return codage

def conversion(dossier,fichier): # conversion en utf-8
    fichiertemp="utf-"+fichier
    conv = "iconv -f " + 'latin1' + " -t utf-8 "+ fichier + " > " + fichiertemp
    os.system(conv)

def suppression(dossier,fichier):
    ## je sais que c'est étrange mais sinon, le changement
    ## de nom fait apparaître des caractères non conformes
    source="utf-"+fichier
    destination=fichier
    temporaire = "temp-"+fichier
    os.rename(source,temporaire)
    retour = source + " renommé en " + destination
    os.remove(fichier)
    os.rename(temporaire,destination)
    print(retour)

def convertir(dossier,fichier): # conversion des fichiers
    chemin = os.path.join(dossier, fichier)
    if os.path.splitext(chemin)[1] in liste_ext:
        code = typecode(dossier,fichier)
        if code =='windows-1251' or code == 'ISO-8859-2' \
        or code == 'ISO-8859-2' or code == 'latin1' \
        or code == 'windows-1255':
            conversion(dossier,fichier)
            retour = fichier + ' converti de ' + code + ' en utf-8'                 
        elif code == 'utf-8' or code == 'UTF-8':
            retour = fichier + ' déjà au format ' + code
        else:
            try:
                retour = fichier + ' au format ' + code
            except:
                retour=None
                pass
        print(retour)
    

curdir='.' # remplacer ici par le chemin

for dossier, sous_dossiers, fichiers in os.walk(curdir):
    if fichiers != []:
        print("Sous dossiers : %s" % sous_dossiers)              
        for fichier in fichiers:
            try:
                convertir(dossier,fichier)
            except:
                continue
        
rep = input("On efface les fichiers non codés en utf-8 et on les renomme ? (O / N) ATTENTION : plus de fichiers ISO ensuite !")
if rep == 'O':
    for dossier, sous_dossiers, fichiers in os.walk(curdir):
        if fichiers !=[]:
            for fichier in fichiers:
                if os.path.exists(fichier) and os.path.exists("utf-"+fichier):
                    suppression(dossier,fichier)
                else:
                    if os.path.exists(fichier):
                        print(fichier, "intact")

Ce code m’a paru beaucoup trop long pour le peu de chose qu’il doit faire. De plus, la commande iconv ne semblait pas trop fonctionner… J’ai donc écrit un petit programme tout bête.

Mon programme Python pour convertir l’encodage d’un fichier

# Auteur: Stéphane Pasquet
# Site : https://mathweb.fr
# Date : 2021/05/27

from os import walk, getcwd, mkdir
from os.path import isdir
from chardet import detect

rep_courant = getcwd()
directory_utf = rep_courant + '\\utf8'

if not isdir(directory_utf):
    mkdir(directory_utf)

for dossier, sous_dossiers, fichiers in walk(rep_courant):
    for fichier in fichiers:
        if fichier[-3:] == 'tex':
            d = rep_courant + '\\' + fichier
            fich = open(d,'rb')
            txt = fich.read()
            fich.close()
            codage = detect(txt)['encoding']
            if codage != 'utf-8':
                Fichier = open(d , 'r')
                contenu = ""
                for ligne in Fichier.read():
                    contenu += str(ligne)

                Fichier2 = open( directory_utf + '\\' + fichier , 'w' , encoding = 'utf-8')
                Fichier2.write( contenu )
                Fichier2.close()

L’idée ici est de sauvegarder ce script Python dans le répertoire des fichiers à convertir, puis de parcourir ce répertoire: si on rencontre un fichier “.tex” (l’extension peut bien sûr être choisie à votre convenance) et si l’encodage n’est pas UTF-8, alors on l’ouvre en mode binaire et on réécrit son contenu dans un autre fichier qui sera sauvegardé en UTF-8 dans un répertoire (ici, nommé “utf8”).

Cet article a 3 commentaires

  1. Nicolas Patrois

    Puisque tu sembles utiliser Linux, iconv sert à changer l’encodage d’un fichier, mais il existe aussi konwert qui fait le même boulot. Par exemple konwert any-utf8 monfichier.txt convertit monfichier.txt encodé en quelque chose (déterminé par konwert) vers utf8. Il permet même de convertir les codes HTML en utf8 ou l’inverse, par exemple é en é, ou en (ou vers) tout un tas d’autres formats exotiques (ascii, iso*, cp*, mac*, html* et même tex).
    iconv et konwert sont installés chez moi et il est parfois plus pratique d’utiliser un script shell pour convertir une volée de fichiers plutôt que de passer par Python.

    1. Je ne suis pas sous Linux, mais sous Windows 10. Effectivement, sous Linux, iconv fonctionne bien. Je ne connaissais pas konwert, mais c’est normal, n’étant plus linuxien depuis fort longtemps :-).
      Mais sous windows, je n’ai pas eu vent d’une commande shell adéquate, ce qui est, en effet, bien plus pratique que de passer par python… quoi que…
      C:\Users\MonRep> py monscriptreencode.py
      ça marche pas mal non plus, à condition que le fichier Python contienne les bonnes instructions pour ré-encoder les fichiers courant du répertoire courant.

  2. Nicolas Patrois

    C’est peu étonnant qu’iconv ne soit pas de base dans Windows, il fait partie (dans Debian) du paquet libc-bin, un paquet GNU.
    On peut néanmoins le trouver pour Windows dans Cygwin.

Laisser un commentaire