{"word_count": 1007, "character_count": 7558}
Un petit billet rapide, sans aucune prétention. Juste pour revenir sur des trucs bizarres sur l'encodage... J'avais commencé à m'y intéresser il y a 3 ans, alors que je discutais avec des utilisateurs de R en Inde et au Japon. Mais revenons à la base... Si on regarde la page "unicode" de Wikipedia (ou plus précisément, si on regarde le code source, on peut avoir des informations (dans les métadonnées) : en l’occurrence, on voit que la page est encodée en UTF-8C'est cohérent car de plus en plus de documents en ligne semblent encodé dans ce format. Si on revient à la source, l'encodage c'est lié au passage par les bytes 0/1. Plein de sites expliquent (en gros) la philosophie. Quand j'étais petit, on nous expliquait les caractères ASCII, qui utilisent 7 bits ce qui permet de disposer  128 caractères uniquement, numérotés de 0 à 127.  Genre "A" était le 65ème caractère, et "a" le 97ème. Il y avait des symboles exotiques (comme "@" qui est le 64ème) ou la ponctuation, mais pas d'accents, comme "à". Si on veut les lettres avec des accents, il faut plus que 128 caractères. Est-alors arrivée ISO/CEI 8859, qui proposait d'encoder les caractères sur 8 bits (et pas 7). On parle aussi de ISO 8859-1 plus populaire sous le nom "latin-1" très populaires dans les pays latins, avec le "à", et puis on a continué d'enrichir pour arriver au ISO 8859-15 (latin-9) avec dedans le symbole "€". Pour les langues asiatiques, il a fallu enrichir encore. Bref, c'est un jeu sans fin. Dans les années 90, est arrivée la norme ISO 10646 correspondant au "jeu universel de caractères" ou UCS pour Universal Character Set (en anglais), qui donnera Unicode. Je crois que les puristes font la différence entre les jeux de caractères (l'ensemble de caractères auxquels on attribue à chacun un point de code unique, la liste des caractères ASCII par exemple) et l'encodage (qui est la façon de représenter ce point de code en mémoire). Mais on va faire simple...Là où ça se complique c'est que les OS utilisaient (par défaut) des encodages différents. Sous Windows, UTF-16 et Unicode sont majoritairement utilisé. Sous Mac OS,il y avait un truc appelé MacRoman mais il semble que UTF-8 l'emporte aujourd'hui. Enfin, sous linux, historiquement c'était du latin-1 par défaut, mais progressivement l'UTF-8 semble prendre le dessus. Bref, tous ceux qui naviguent entre les OS le savent : les accents c'est l'enfer. Et le principal soucis c'est qu'il est impossible, quand on récupère un fichier d'avoir son encodage a priori. Regardons le fichier suivant BaseANSI.txtOn peut tenter de regarder s'il y a des sortes de méta-données dans le document...mais ce n'est pas le cas. Le document est un document brut, avec juste les données, et aucune métadonnées. Rien sur l'encodage (en particulier, car c'est ce qui nous intéresse aujourd'hui). Pour l'anecdote, si au lieu d'ouvrir le fichier avec mon bloc-note sous Windows, on tente sur un mac, on aEt quand je passe par le terminal DOS sous Windows, c'est la même chose (ce qui est un peu rassurant)Regardons un autre fichier BaseUNICODE.txt. Si vous voyez une différence avec l'autre, dites le moi...Pourtant il y en a une : la preuve, dans un terminal, on peut lire les accents du fichier,Un dernier ? Regardons BaseUTF8.txt,Là encore, on a l'impression d'avoir le même fichier. Et pourtant non.Commençons par récupérer les trois fichiers (via R)download.file(url="http://freakonometrics.free.fr/BaseUTF8.txt",destfile="BaseUTF8.txt")download.file(url="http://freakonometrics.free.fr/BaseANSI.txt",destfile="BaseANSI.txt")download.file(url="http://freakonometrics.free.fr/BaseUNICODE.txt",destfile="BaseUNICODE.txt")Techniquement, ces documents sont différents, même si dans le bloc note, on ne voyait rien : il n'ont pas la même taille !file.size("BaseUNICODE.txt")[1] 322file.size("BaseANSI.txt")[1] 163file.size("BaseUTF8.txt")[1] 171On peut essayer de les lire, pour voir...read.table("BaseANSI.txt",header=TRUE,sep=";")                       Département No Habitants1                              Ain 01    6318772                          Ardèche 07    3242093                 Bouches-du-Rhône 13   20166224                     Corse-du-Sud 2A    1527305 Côte-dOr;21;533147\nCôtes-dArmor 22    598357On a un petit soucis avec l'apostrophe, mais rien de graveread.table("BaseANSI.txt",header=TRUE,sep=";",quote="\"")       Département No Habitants1              Ain 01    6318772          Ardèche 07    3242093 Bouches-du-Rhône 13   20166224     Corse-du-Sud 2A    1527305        Côte-d'Or 21    5331476    Côtes-d'Armor 22    598357R arrive parfaitement a lire (sur mon ordinateur du moins) cette première base de données. Tentons une seconderead.table("BaseUTF8.txt",header=TRUE,sep=";",quote="\"")    ï..DÃ.partement No Habitants1               Ain 01    6318772          ArdÃ¨che 07    3242093 Bouches-du-RhÃ´ne 13   20166224      Corse-du-Sud 2A    1527305        CÃ´te-d'Or 21    5331476    CÃ´tes-d'Armor 22    598357On a manifestement un soucis, un soucis d'encodage. Le soucis c'est que, d'ordinaire, on ne sait pas comment le fichier a été encodé. Et comme on l'a vu, il n'y a pas de métadonnées qui nous donne l'encodage. Comment faire ? Heureusement, il existe une fonction sous R qui devine l'encodage. Littéralement.library(readr)guess_encoding("BaseUTF8.txt", n_max = 1000)# A tibble: 3 x 2  encoding   confidence             1 UTF-8           1.00 2 ISO-8859-1      0.6203 ISO-8859-2      0.430Autrement dit, le best-guess est ici un encodage UTF-8. Essayons pour voir,read.table("BaseUTF8.txt",header=TRUE,sep=";",encoding="UTF-8",quote="\"")  X.U.FEFF.Département No Habitants1                  Ain 01    6318772              Ardèche 07    3242093     Bouches-du-Rhône 13   20166224         Corse-du-Sud 2A    1527305            Côte-d'Or 21    5331476        Côtes-d'Armor 22    598357Ça marche ! ou disons que ça marche presque. J'ai un soucis dans mes libellés de variables. Mais disons que c'est anecdotique ici.Tentons le dernier fichierread.table("BaseUNICODE.txt",header=TRUE,sep=";",quote="\"")  ÿþD1  NA2  NA3  NA4  NA5  NA6  NA7  NA8  NAComme ça ne marche pas, essayons d'avoir un best-guess sur l'encodageguess_encoding("BaseUNICODE.txt", n_max = 1000)# A tibble: 3 x 2  encoding   confidence             1 UTF-16LE        1.00 2 ISO-8859-1      0.5303 ISO-8859-2      0.270On en tient un !read.table("BaseUNICODE.txt",header=TRUE,encoding="UTF-16LE")  ÿþD1  \n2   B3  \n4   C5  \n6   C7  \n8   CDamned, ça ne marche pas... Heureusement, Ewen est venu à ma rescousse. La solution est relativement étrangeread.table("BaseUNICODE.txt",header=TRUE,fileEncoding="UTF-16LE", sep=";", quote="")       Département No Habitants1              Ain 01    6318772          Ardèche 07    3242093 Bouches-du-Rhône 13   20166224     Corse-du-Sud 2A    1527305        Côte-d'Or 21    5331476    Côtes-d'Armor 22    598357Oui, on n'utilise pas l'encodage via "encoding" mais "fileEncoding" ! Subtil non... Cela dit, si on voulait être cohérent on devrait utiliser la fonction du package pour lire la base, non ? Car dans le package "readr" il y a une fonction "read_table"read_table("BaseUNICODE.txt",locale=locale(encoding = "UTF-16LE"))Error in guess_types_(datasource, tokenizer, locale, n = guess_max) :   Incomplete multibyte sequenceSauf que quand on la lance, on a un message d'erreur... Bref, l'encodage c'est compliqué. C'est ce qui est expliqué dans le forum de discussion du package cela dit. Je ne suis pas sûr que mon billet serve à quoi que ce soit, mais je voulais garder une trace de tout ça !