Illustration montrant un fichier texte mal encodé avec des caractères étranges et des � à gauche (emoji horrifié) et un fichier correctement encodé avec du texte lisible à droite (emoji lunettes de soleil), symbolisant la correction des problèmes d'encodage.

Guide complet sur l’encodage : comment corriger les caractères bizarres dans les fichiers texte ?

Un de nos clients a signalé un problème avec un fichier CSV exporté par notre application. Depuis que l’application accepte les caractères spéciaux, lorsqu’il ouvre ce fichier texte dans Excel, il voit des caractères bizarres à la place des accents. Ce type de problème est courant et est généralement dû à un mauvais encodage des caractères dans le fichier texte. Dans cet article, nous allons voir comment corriger les caractères bizarres dans les fichiers texte. Nous détaillerons les causes probables du problème et expliquerons comment le résoudre en analysant du code source Python.

Pourquoi les caractères bizarres apparaissent-ils dans les fichiers texte ?

L’ère de l’ASCII et ses limitations

À l’aube de l’informatique, les fichiers texte étaient généralement encodés en ASCII, un jeu de caractères qui ne prend en charge qu’un nombre limité de caractères spéciaux. La table de caractères ASCII permet à un programme informatique de représenter des caractères en utilisant des nombres entiers. Par exemple, le caractère « A » est représenté par le nombre entier 65 en ASCII. Cependant, l’ASCII ne prend pas en charge les caractères accentués, tels que « é », « à », « ç », etc. Cela est lié à la limitation de l’ASCII qui représente un caractère sur 7 bits, soit 128 caractères différents.

L’évolution des encodages de caractères

Pour résoudre ce problème et étendre le nombre de caractères pris en charge, de nouveaux encodages de caractères ont été créés, tels que ISO-8859-1, Windows-1252, UTF-8, UTF-16, etc. Ces encodages de caractères prennent en charge un plus grand nombre de symboles, y compris les caractères accentués et spéciaux.

Comparaison des encodages : ISO-8859-1 vs UTF-8

Chacun de ces encodages de caractères utilise une table de caractères et une méthode de codage différente pour les représenter. Par exemple, avec l’encodage ISO-8859-1, le caractère « é » est représenté par le nombre entier 233, tandis qu’avec l’encodage UTF-8, il est représenté par une séquence de plusieurs octets (sa représentation hexadécimale est « C3 A9 »).

L’importance de l’encodage pour les développeurs

En tant que développeur, nous nous soucions rarement de l’encodage des caractères lors de l’écriture de code, car la plupart des langages de programmation modernes gèrent automatiquement les différents encodages de caractères. Cependant, lorsque nous écrivons des fichiers texte ou exportons des données dans un format texte, nous devons être conscients de l’encodage de caractère utilisé pour éviter les problèmes de caractères bizarres.

Quelles sont les causes des caractères bizarres dans les fichiers texte ?

Les fichiers sont des séquences d’octets et ne contiennent aucune information sur l’encodage des caractères utilisé pour les représenter. Ces fichiers sont généralement produits ou consommés par des applications qui supposent un encodage de caractères connu des deux parties. Si l’encodage de caractères utilisé pour lire ou écrire un fichier texte est différent de celui attendu par l’autre application, des caractères bizarres peuvent apparaître.

Production de fichiers texte avec un mauvais encodage

Certains langages de programmation utilisent par défaut un encodage de caractères spécifique lorsqu’ils lisent ou écrivent des fichiers texte. Par exemple, Java et Python utilisent l’encodage de la plateforme sur laquelle le programme s’exécute. Sur Windows, si vous écrivez un fichier texte en utilisant l’encodage UTF-8 et que vous ne spécifiez pas l’encodage lors de la lecture de ce fichier, des caractères bizarres peuvent apparaître côté consommateur car l’encodage du système est généralement Windows-1252.

Consommation de fichiers texte avec un mauvais encodage

De la même manière, si vous lisez un fichier texte avec un encodage différent de celui utilisé pour l’écrire, des caractères bizarres peuvent apparaître, voire causer l’arrêt prématuré du programme.

Par exemple, en utilisant le code source Python suivant, nous pouvons lire un fichier texte date.txt encodé en UTF-8 et le décoder en ISO-8859-1 :

# /decode.py
with open('data.txt', 'r', encoding='iso-8859-1') as fp:
    print(fp.read())

La lecture du fichier avec l’encodage ISO-8859-1 produit l’écart suivant :

Texte en UTF-8Texte décodé en ISO-8859-1
Par une belle journée d'été en forêt, nous trouvâmes divers bancs conçus lors d'un concours communal.
Ces bancs ornaient une allée fleurie, et nous choisîmes de passer par là pour rejoindre notre grand-mère.
Par une belle journée d'été en forêt, nous trouvâmes divers bancs conçus lors d'un concours communal.
Ces bancs ornaient une allée fleurie, et nous choisîmes de passer par là pour rejoindre notre grand-mère.

À l’inverse, si le fichier texte est encodé en ISO-8859-1 et décodé en UTF-8, l’exécution du code Python avec le paramètre encoding="utf_8" donnera le résultat suivant :

$ python decode.py
Traceback (most recent call last):
  File "./decode.py", line 2, in <module>
    print(file.read())
          ^^^^^^^^^^^
  File "<frozen codecs>", line 322, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 19: invalid continuation byte

Le programme lève une exception UnicodeDecodeError car il ne peut pas décoder le caractère é en UTF-8.

Autre erreur d’encodage lors de la production d’un fichier texte

Une autre source d’erreur d’encodage peut provenir du code source lui-même, qui peut être encodé avec un jeu de caractères différent de celui utilisé pour lire ou écrire un fichier texte.

Analysons un exemple de code source écrit en Python :

# /encode.py
# -*- coding: iso-8859-1 -*-

import sys

sys.stdout.write("journée d'été en forêt")

Dans cet exemple, le code source est sauvegardé en UTF-8 par l’éditeur de texte. Cependant, le commentaire # -*- coding: iso-8859-1 -*- indique à Python que le code source est encodé en ISO-8859-1. Lorsque le code est exécuté, le terminal affiche des caractères bizarres à la place des caractères accentués :

$ python encode.py
journée d'été en forêt

Quelles stratégies adopter pour limiter les caractères bizarres dans les fichiers texte ?

Stratégie 1 : Utiliser un encodage cohérent pour l’ensemble du code source

La plupart des éditeurs de texte modernes permettent de spécifier l’encodage du fichier source, et par défaut, l’encodage est généralement défini en UTF-8. Il est recommandé de choisir un encodage unique pour l’ensemble du code source d’un projet afin d’éviter les incohérences d’encodage.

Stratégie 2 : Spécifier l’encodage lors de la lecture ou de l’écriture de fichiers texte

Description de la stratégie

Lorsqu’un programme lit ou écrit un fichier texte, il manipule des octets sans aucune information sur l’encodage des caractères. Certains langages de programmation peuvent choisir un encodage par défaut pour lire ou écrire des fichiers texte. Il est donc important de spécifier explicitement l’encodage des caractères lors de ces opérations pour éviter les caractères bizarres.

Pour garantir la cohérence de l’encodage, l’objectif est de spécifier avec le client et les partenaires le format d’encodage des fichiers texte échangés. Il sera alors possible de définir explicitement l’encodage dans le code source pour la lecture ou l’écriture de ces fichiers.

Correction des caractères bizarres dans le fichier CSV avec Python

Par exemple, le problème rencontré par notre client avec le fichier CSV exporté est lié à l’encodage utilisé par défaut par Excel pour ouvrir ce type de fichier. Lors de l’ouverture du fichier CSV, Excel ne détecte pas automatiquement l’encodage des caractères et il ne demande pas à l’utilisateur de le spécifier. Par conséquent, les caractères accentués ne sont pas affichés correctement. Pour résoudre le problème côté producteur, nous avons simplement ajouté l’encodage Windows-1252 lors de l’écriture du fichier CSV.

# ...
with open("export.csv", "w", encoding="cp1252", newline='') as fp:
    writer = csv.writer(fp, delimiter=',', quotechar='"')

    writer.writerow(columns)
    writer.writerows(data)

Stratégie 3 : Implémenter un mécanisme de détection automatique de l’encodage

Si les deux méthodes précédentes permettent de sécuriser le fonctionnement de vos algorithmes en respectant un contrat d’interface explicite, il est possible d’aller plus loin en implémentant un mécanisme de détection automatique de l’encodage des fichiers texte. Cette approche peut être utile si l’algorithme doit traiter des fichiers texte provenant de sources diverses et dont l’encodage est inconnu.

Comment fonctionne la détection automatique de l’encodage ?

Les algorithmes de détection de l’encodage réalisent une analyse du contenu binaire d’un fichier texte pour déterminer un taux de correspondance avec un ensemble d’encodages connus. En effet, les jeux de caractères utilisent parfois les mêmes règles pour encoder un caractère spécial. Par exemple, les encodages ISO-8859-1 et Windows-1252 sont très similaires. Il est donc difficile de déterminer précisément l’encodage du fichier. Néanmoins, plus le fichier contiendra de caractères spéciaux, plus l’algorithme de détection sera performant.

Doit-on implémenter nous même cet algorithme de détection automatique de l’encodage ?

Aujourd’hui, de nombreuses librairies et outils permettent de détecter automatiquement l’encodage des fichiers texte. Par exemple, les librairies Python chardet ou charset-normalizer sont d’excellents choix. Ces librairies appliquent justement la logique décrite précédemment pour déterminer l’encodage le plus probable d’un fichier texte.

Détection de l’encodage du fichier texte avec charset-normalizer

Installation de charset-normalizer

Vous trouverez les instructions d’installation de la librairie charset-normalizer dans sa documentation officielle. Pour l’installer, nous pouvons utiliser pip :

$ pip install charset-normalizer
Collecting charset-normalizer
  Downloading charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl (101 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 101.8/101.8 kB 1.9 MB/s eta 0:00:00
Installing collected packages: charset-normalizer
Successfully installed charset-normalizer-3.4.0
Détection de l’encodage d’un fichier texte

Nous allons tenter de détecter l’encodage du fichier texte data.txt précédent avec charset_normalizer.

# /detect_encoding.py
import charset_normalizer


# Analyse du fichier data.txt
result = charset_normalizer.from_path("data.txt").best()
if result is not None:
    print(result.encoding)

    with open("data.txt", "r", encoding=result.encoding) as fp: # <1>
        print(fp.read())
else:
    print("No encoding detected")
    exit(1)
1

Utilisation de l’encodage détecté par charset_normalizer pour lire le fichier.

En exécutant ce script, l’encodage du fichier data.txt est détecté comme utf_8 et le contenu est correctement affiché.

En ré-exécutant le script avec un fichier texte encodé en ISO-8859-1, l’encodage détecté est cp1252 (c’est-à-dire Windows-1252). Bien que l’encodage détecté soit inexacte, la similarité des deux encodages permet un décodage correct. Nous n’obtenons donc aucun caractère bizarre dans le terminal.

Stratégie 4 : Sécuriser la lecture d’un fichier texte avec un encodage inconnu

La détection automatique de l’encodage permet de réduire les erreurs de décodage, mais elle n’est pas infaillible. En effet, il est possible que l’algorithme ne parvienne pas à déterminer l’encodage du fichier. Il est fréquent de rencontrer du code source dont certaines portions sont encodées en Windows-1252 alors que le reste est en UTF-8. Il est donc recommandé de définir un encodage par défaut ou d’utiliser l’encodage le plus probable, tout en implémentant une méthode de gestion des erreurs.

En Python, la fonction open() permet de définir un paramètre encoding pour préciser l’encodage, ainsi qu’un paramètre errors pour gérer les erreurs de décodage. Ce dernier offre différentes stratégies, comme ignorer les caractères invalides, les remplacer par un symbole de substitution, etc. (voir les méthodes de gestion d’erreur avec Python).

L’exemple suivant illustre comment lire un fichier texte qui devrait être encodé en UTF-8, et comment gérer les erreurs de décodage en remplaçant les caractères invalides par un point d’interrogation :

# /read_safe.py
with open('output.txt', 'r', encoding='utf_8', errors='replace') as fp:
    print(fp.read())

En exécutant le script, les caractères invalides sont remplacés par le caractère  :

$ python read_safe.py
Par une belle journ�e d'�t� en for�t, nous trouv�mes divers bancs con�us lors d'un concours communal. # <1>
Ces bancs ornaient une allée fleurie, et nous choisîmes de passer par là pour rejoindre notre grand-mère.
1

L’apparition des caractères invalides s’explique car la première ligne était encodée en ISO-8859-1.

Conclusion

Dans cet article, nous avons exploré les causes courantes des caractères bizarres dans les fichiers texte et proposé des stratégies efficaces pour éviter ce problème. Nous avons discuté des différents types d’encodage, des erreurs fréquentes lors de la production et de la lecture des fichiers texte, ainsi que des solutions pratiques en Python pour détecter et corriger les encodages incorrects.

En suivant ces recommandations, vous serez en mesure de diagnostiquer et de résoudre les problèmes d’encodage, assurant ainsi la compatibilité de vos fichiers texte avec les applications tierces. Que vous choisissiez d’utiliser un encodage cohérent, de spécifier explicitement l’encodage lors de la lecture et de l’écriture, ou d’implémenter un mécanisme de détection automatique, ces stratégies vous aideront à maintenir l’intégrité de vos données textuelles.

N’hésitez pas à mettre en pratique ces conseils et à partager vos expériences. Si vous avez des questions ou des suggestions, laissez un commentaire ci-dessous.

Laisser un commentaire