Régionalisation

Programming, Localization, Character Encoding · course

Browse all programmation documents

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 ’\&amp;span’

• Comportant un caractère Unicode U+2660

<span

onclick=‘javascript:alert(\’"\\&amp;amp;span\’);’>&lt;span&gt;&#x2660;</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