Régionalisation
Frédéric Claux - 2019
CC BY-NC-ND – [email protected]
De quoi nous allons parler
• Locale
• Culture
• Jeu de caractères (charset)
• ASCII
• Latin-1
• Unicode
• UTF-8
• BOM (Byte Order Mark)
• etc.
Globalisation, localisation
• Globalisation
• Capacité à écrire des programmes pour plusieurs cultures
• Sans avoir à faire du code spécialement pour telle ou telle culture
• Localisation
• Ecrire du code spécifiquement pour telle ou telle culture
• Intérêt pour les utilisateurs
Des caractères aux octets
• Retranscription des caractères sous forme de suite d’octets
• Intérêt pour les programmes
• Pour le stockage
• Pour les traitements
• Pour la gestion des entrées/sorties (affichage, ou même le clavier)
Deux parties
• Locale, culture (utilisateurs)
• Encodage de caractères (programmes)
Deux parties
• Locale, culture (utilisateurs)
• Encodage de caractères (programmes)
Locale, culture
• Langue + territoire, et ensemble de données liées
• Exemple: fr_FR, fr_CA, en_GB, en_US
• Formattage des
• Dates
• 26 mars 2019, 26/3/2019 (France)
• March, 26 2019, 3/26/2019 (Etats-Unis, Royaume-Uni)
• Nombres
• 1 000 personnes (France)
• 1,000 personnes (Etats-Unis)
• Nombres (monnaie (currency))
• £1,000, 1 000€, $1,000
Locales installées
• Windows
• Toutes
• Unix
• Voir les locales installées sur le système
• cat /etc/locale.gen
Locale système, utilisateur
• Locale système
• Utilisée comme locale utilisateur si l’utilisateur n’a pas défini de locale
• Windows
• GetSystemDefaultLCID
• Locale utilisateur
• Utilisée si l’utilisateur a expressément défini une locale
• Windows
• GetUserDefaultLocaleName/GetUserDefaultLCID
• Unix
• $LANG (partie locale, première partie)
• Locale d’un processus/thread
• Windows
• GetThreadLocale
• Unix
• valeur renvoyée par setlocale(LC_ALL)
Exemple d’utilisation d’une locale
• Représenter les nombres à l’écran
• J’ai 1000 ballons
• Comment afficher cela ?
Utiliser une locale
Advertisement
• Java
• Active
• String.format(« You have %d balloons », numBalloons);
• Explicite
• String.format(Locale.US, « You have %d balloons », numBalloons);
Utiliser une locale
• C
• Active
• // La locale par défaut s’appelle « C » (renvoyée par setlocale(LC_ALL, NULL))
• printf(« %.2f », 1000.01);
• Affiche 1000.01
• Explicite
• setlocale(LC_ALL, « fr_FR.utf8 »);
• printf(« %.2f », 1000.01);
• Affiche 1000,01
Utiliser une locale
• C++
• Active
• // La locale par défaut s’appelle « C »
• std::cout << 1000.01;
• Affiche 1000.01
• Explicite
• std::locale::global(std::locale(« fr_FR.utf8 »));
• std::cout << 1000.01;
• Affiche 1000,01
Utiliser explicitement une locale
• Navigateur
• Active: locale de la session
• HTTP Accept-Language (non accessible depuis Javascript ou le DOM)
• Javascript: navigator.language
• Utilisation explicite
• Date e = new Date(Date.UTC(2012, 11, 20, 3, 0, 0));
var options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric’ };
alert(e.toLocaleDateString('de-DE', options));
Installer de nouvelles locales sous Unix
• Voir les locales installées sur le système
• cat /etc/locale.gen
• Installation de nouvelles locales
• Décommenter des locales commentées avec « # » dans locale.gen
• Lancer sudo locale-gen
Deux parties
• Locale, culture (utilisateurs)
• Encodage de caractères (programmes)
A quoi est rattaché l’encodage ?
• Un caractère est un caractère
• Ce n’est en rien un concept informatique
• A quel moment « quitte-t-on » l’univers des caractères ?
• A quel moment est-on obligé de considérer qu’un caractère a une
représentation « technique » ?
Encodage, utilité
• Entrées/sorties sur les fichiers
• Interopérabilité
• Entrées/sorties mémoire
• Je passe une chaine de caractères à telle fonction de telle bibliothèque écrite
en tel langage, comment dois-je la représenter, puisqu’à l’évidence la chaine
de caractères doit avoir une « empreinte » mémoire ?
A quoi est rattaché l’encodage ?
• Inclus stdin, stdout et stderr
• le cas échéant
• L’encodage n’est PAS rattaché aux fichiers
• Les fichiers et flux n’ont PAS un encodage qui leur est assigné
• C’est au programme qui interprète le contenu de fichiers d’être au
courant de l’encodage
De quoi est constitué l’encodage
• D’un jeu de caractère
• D’un format de transfert, qui traduit un caractère de ce jeu sous
forme d’octets
Jeu de caractères
• Représentation d’un caractère sous forme de numéro dans un jeu de caractères
• Par exemple, ‘é’
• se représente par le numéro 169 en Latin-1
Advertisement
• se représente par le numéro 169 en Unicode
• ne peut pas se représenter en US-ASCII
• Autre exemple, ‘々’
• se représente par le numéro 2139 en JIS X 0208
• se représente par le numéro 3005 en Unicode
• ne peut pas se représenter un US-ASCII, ou en Latin-1
• Autre exemple, ‘€’
• Se représente en Latin-15 ou en Unicode, mais pas en Latin-1 ou en US-ASCII
• Certains jeux de caractères ont un nom courant et un nom officiel
• Latin-1 (nom courant) est en fait ISO-8859-1 (nom officiel), Latin-15 est ISO-8859-15
• Jusqu’ici 1 caractère = 1 numéro (entier) dans un jeu de caractères
Encodage
• Représentation sous forme d’octet(s) d’un numéro dans un jeu de
caractères
• C’est la première fois aujourd’hui que nous parlons d’octets
• On parle d’encodage, ou de format de transfert d’un jeu de caractères
• Quand un jeu de caractères a moins de 256 caractères, c’est facile:
le numéro est stocké dans un octet.
• Ainsi, Latin-1 (ISO-8859-1) est à la fois
• Un jeu de caractère
• Un encodage (où 1 caractère est sauvegardé sous forme d’1 octet)
Unicode
• Quand un jeu de caractères (comme par exemple Unicode) a plus de
256 caractères, il faut décomposer ce numéro en octets
• Puisque pour stocker en mémoire ou enregistrer sur disque, il faut bien que
les choses se terminent sous forme d’octets…
• Prenons un exemple
• Unicode a plus de 109 000 caractères
• Pour sauver chaque caractère, il nous faut au moins 3 octets
(2 octets = 16 bits = représenteraient 65 536 caractères seulement)
UTF-32
• Représente n’importe quel caractère Unicode sous forme de 4 octets
• 4 octets facilement manipulables sur un processeur
(32 bits ; taille d’un registre x86 par exemple)
UTF-8, UTF-16
• Est-il judicieux de toujours représenter un caractère avec 3 octets ?
• Non ! Beaucoup trop de place mémoire
• Idéal:
• Sauver 1 octet la plupart du temps, 2 octets parfois, 3 octets dans de rares cas
• L’encodage UTF-8 fait ceci
• Idéal pour les langues occidentales (~200 caractères utiles en pratique souvent sauvés
sous forme d’1, ou à la limite 2 octets au maximum)
• Pour les langues asiatiques, il est fréquent d’utiliser de nombreux caractères
dans un texte
• Sauver 1 mot de 16-bits la plupart du temps, parfois 2 mots.
• UTF-16
UTF-8, UTF-16, UTF-32, des mots aux octets
• Unicode est un jeu de caractère (juste des numéros, pas des octets)
• UTF-32 représente chaque caractère sous forme d’1 mot de 32 bits
• UTF-16 représente chaque caractère sous forme d’1 ou 2 mots de 16
bits
• UTF-8 représente chaque caractère sous forme d’1, 2 ou 3 mots de 8
bits
• Chaque mot est, à son tour, transformé en suite d’octets
Big Endian, Little Endian
• Supposons que l’on souhaite utiliser UTF-16
pour transformer en octets le caractère U+10437 (𐐷)
• En UTF-16, ce caractère est représenté par
un seul mot de 16 bits = 0xDC37
• Si j’utilise un processeur x86, 0xDC37 arrive en mémoire sous la
forme: 37 DC
• Si j’utilise un processeur SPARC ou 68000, un flux TCP ou même PCI-
express, 0xDC37 arrive sous la forme DC 37
• On parle donc de UTF-16BE et UTF-16LE
• Même remarques pour UTF-32
JIS X 0208 et Shift-JIS
• Même principe que pour Unicode et UTF
• JIS X 0208 est un jeu de caractères
• Shift-JIS est un format de transfert de ce jeu
• Fréquemment utilisé par les japonais
Est-il possible de détecter l’encodage ?
Advertisement
• A partir d’un flux de données,
est-il possible de détecter l’encodage?
• Non. Prenons un exemple:
• C3 A9: est-ce une séquence UTF-8 pour « é »?
• Est-ce un seul caractère UTF-16LE, C3A9 ?
Est-ce un seul caractère UTF-16BE, A9C3 ?
• Ou bien est-ce une séquence de 2 caractères dans un autre encodage ?
Est-il possible de détecter l’encodage ?
• Donc impossible de détecter l’encodage d’un fichier texte?
• Non plus.
• Byte Order Mark en tête de fichier donne 2 informations
• Le fichier est Unicode
• Spécifie le format de transfert, eg UTF-16 ou 32
• Spécifie Little Endian / Big Endian (LE/BE)
• Hélas, très peu utilisé
• Parasite le début du fichiers avec deux octets FE FF
Est-il possible de détecter l’encodage ?
• ISO-8859-1 vs UTF-8 peau de banane classique
• Sous Windows, l’encodage par défaut en Europe de l’ouest est Windows1252,
un cousin de Latin-1
• Sous Linux, l’encodage par défaut est UTF-8
• Erreurs d’interprétation de Frédéric -> Fr%E9d%E9ric ->
Fr%C3%A9d%C3%A9ric quasiment inévitables…
• Outils à la rescousse
• Cas d’école: Git, SVN, VSTF, Mercurial
• Gestion de l’encodage (gestion des changements de ligne aussi, \r\n, \n etc.)
Edition du code source
• Prudence si vous définissez des chaînes (ou même des commentaires)
avec des accents
• eg.
• char *foo = « Frédéric »;
• Ce fichier va être sauvegardé par l’éditeur de texte
• quel jeu de caractère/encodage utilisé pour créer ce fichier texte ?
• quel jeu de caractère/encodage le compilateur va-t-il utiliser ?
(Indice: le compilateur est un programme comme les autres, qui lit la locale
de l’utilisateur etc. etc.)
(Indice2: rappelons-nous qu’il n’est pas possible de « détecter » l’encodage)
• quel est l’éditeur utilisé (Sublime/bloc notes ?), sur quel système ?
Encodage actif de la console
• Locale courante
• chcp
• Changement de locale
• Sous CMD
• chcp <codepage Microsoft>
65001 = UTF-8
850 = US-ASCII
1252 ~= ISO-8859-1 (Latin 1)
• Sous Powershell
• $OutputEncoding = [Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8
Encodage d’une chaine avec l’encodage actif
• Unix
• Unix
• echo étudiant | xxd –pr
ou
echo étudiant | hexdump –C
• Windows
• echo étudiant > test.txt
• > powershell
• > Format-Hex test.txt
• localectl status
(notez la première partie de LANG,
par exemple fr_FR)
• localectl set-locale LANG=fr_FR.utf8
(recopier la première partie,
changer la seconde)
• Windows
• chcp
• chcp 1252
• chcp 65001
Manipuler des caractères spéciaux
• Mot polonais « Wyjście »
Advertisement
• C
• char
• char c[] = "wyj\u015Bcie";
for (char& c : cs)
{
// examen de la valeur de c
} // examen du nombre total de caractères
• VC++: 7 caractères, et le 4ème caractère est invalide
• GCC: représentation UTF-8 de « Wyjście », sur 8 ‘char’.
• wchar_t
• wchar_t c[] = L"wyj\u015Bcie";
• sizeof(wchar_t) == 2 sous Visual C++ (catastrophe), 4 sous GCC.
• GCC gère correctement les caractères UTF-32, eg. wchar_t c[] = L"\U0002008A";
• char16_t, char32_t… peu de support
Manipuler des caractères spéciaux
• Mot polonais « Wyjście »
• Java
• String s = "wyj\u015Bcie";
• Stockage interne de la JVM : UTF-16
• s.charAt(<index>) ne fait que décomposer la chaine en mots de 16-bits.
En présence d’un caractère Unicode tenant sur 2 mots 16-bits, charAt(<index>) ne
renvoie qu’un seul mot (celui à l’index correspondant)
• Donc Char == mot 16 bit
• Héritage de 1995 où Unicode n’avait que 40 000 caractères.
• Même remarque pour .length()
• Solution: s.codePointAt(<index>), renvoie un int, correspondant au vrai caractère
Unicode composé d’un ou plusieurs mots 16 bits UTF-16.
Utilisation d’APIs pour se soustraire de la
problématique d’encodage
Utilisation d’un DOM ou d’un writer Xml
• Supposons que nous voulions
• Créer un fichier XHTML
• Avec un élément SPAN ayant pour texte « <span> »
• Ayant un gestionnaire onclick en javascript, affichant la chaine ’\&span’
• Comportant un caractère Unicode U+2660
<span
onclick=‘javascript:alert(\’"\\&amp;span\’);’><span>♠</span>
• L’encodage doit être pris intelligemment en charge
Encodage, séquences d’échappement
• SELECT
password
FROM
users
WHERE
name = ‘<name>’
• If password != null
&& password == <password>
OK
Encodage, séquences d’échappement
• SELECT
password
FROM
users
WHERE
name = ‘<name>’
• <name> = « ’;UPDATE TABLE user SET PASSWORD=‘’ WHERE ‘1’ = ‘1 »;
• Injection SQL
Travaux pratiques
• Manipulation de texte avec
• Bash
• C
• C++
• Java
• Page HTML
• PHP
• Affichage d’informations relatives à la locale (culture) utilisateur
• Etude de l’encodage des chaînes de caractères