Le problème de départ est simple à énoncer.
Je dispose d’un fichier de 300000 lignes dont certaines sont en ISO-8859-15 et d’autres en UTF-8. (Il s’agit d’un log IRC.) Je voudrais que tout le fichier soit en UTF-8.
Je connais la commande iconv, qui convertit très bien un fichier (ou une chaîne de caractères) d’un encodage vers un autre. Mais elle ne semble convertir qu’à partir d’un seul encodage à la fois.
En cherchant un peu, je trouve la commande enca (apt-get install enca), qui semble savoir détecter l’encodage d’un fichier. Mais si le fichier en contient plusieurs, elle ne sait plus.
Par ailleurs, cette commande semble avoir du mal à fonctionner lorsque la locale du système est fr_FR.UTF-8.
Solution :
Après avoir repassé ma locale en C, lu un peu la doc, et testé sur quelques lignes de mon fichier, je découvre que enca -i est capable d’affichier « ASCII » si une ligne ne contient pas d’accents, « UTF-8 » si une ligne contient des accents en UTF-8, et « ??? » si la ligne contient des accents en ISO-8859-15.
Cela donne donc la commande suivante :
cat fichier.log | while read -r ligne ; do encoding=$(echo "$ligne" | enca -L none -i) ; if [ "$encoding" = "???" ] ; then echo "$ligne" | iconv -f ISO-8859-15 -t UTF-8 ; else echo "$ligne" ; fi ; done >> fichier.log.conv
Notes :
- Il y a certainement plus simple, mais ayant trouvé une solution qui fonctionne je n’ai pas cherché au delà.
- Cette méthode est donc à considérer comme une base de départ. Si l’on souhaitait l’utiliser dans des scripts à faire tourner régulièrement il faudrait l’améliorer.
- Il est probable qu’on puisse se passer de iconv et tout faire avec enca, mais connaissant déjà la syntaxte d’iconv et sa fiabilité j’ai préféré l’utiliser.
- Le ‘-r’ de read sert à considérer les ‘\’ comme des caractères normaux. Ce n’est pas le cas par défaut.