Chapitre 5.2 : Le codage des caractères⚓︎
I. Table d'encodage⚓︎
A savoir
Un ordinateur ne sait travailler qu'avec des 0 et des 1. Comme les nombres, les textes doivent donc être représentés en machine en binaire avec le format approprié pour éviter les erreurs d'encodage !
Une représentation informatique des caractères nécessite d'associer à chaque caractère une unique séquence d'octets. Cette conversion s'effectue à l'aide d'une table de codage et d'un encodage :
- Une table de codage ou jeu de caractères (charset), associe un entier nommé point de code à un caractère.
- Un encodage associe à un point de code une séquence d'octets.
II. La table de codage ASCII⚓︎
A savoir
Au début des années 1960, devant la multiplication des encodages de caractères et leurs incompatibilités mutuelles, l'ANSI (American National Standards Institute), définit une norme appelée ASCII (American Standard Code for Information Interchange). Ce standard permet de coder 128 caractères sur 7 bits (\(2^7=128\)).
Cette table contient :
- les lettres de l'alphabet latin en majuscule et minuscule et les chiffres de 0 à 9
- des signes de ponctuation et des opérateurs arithmétiques
- des caractères spéciaux (tabulation, retour chariot, nouvelle ligne, etc.) et des caractères de contrôle non imprimables mais utilisés pour les communications.
III. Par la suite d'autres encodages⚓︎
A savoir
La norme ASCII convient bien à la langue anglaise, mais lorsque d'autres personnes que des Américains ou des Anglais ont voulu s'échanger des données textuelles, certains caractères étaient manquants : é, è, à, ñ, Ø, ø, β, β…
Les 7 bits de la table ASCII étaient insuffisants pour ajouter ces nouveaux caractères et la décision de coder les caractères sur 8 bits (2^8=256 caractères) fut prise conduisant à la création de nouvelles tables.
En 1986, la table ISO 8859-1, aussi appelée Latin-1, a vu le jour et était principalement utilisée en Europe car elle ajoutait aux caractères de la table ASCII les caractères de l'alphabet du "latin".
Mais il manquait encore des caractères et après de nombreuses modifications (la dernière en date rajoutant par exemple le symbole €), on a abouti à la célèbre table ISO 8859-15, appelée aussi Latin-9.
Les codes sont donnés en hexadécimal :
- le caractère € correspond au code hexadécimal A4 (intersection de la ligne Ax et de la colonne x4), donc au nombre décimal 164.
- le caractère A correspond au code hexadécimal 41, donc au nombre décimal 65.
65... comme en ASCII ! Oui, la (seule) bonne idée aura été d'inclure les caractères ASCII avec leur même code, ce qui rendait cette nouvelle norme rétro-compatible. Les 128 premiers caractères de cette table, de 00 à 7F en hexadécimal (soit de 0 à 127 en décimal), correspondent exactement aux caractères de la table ASCII. La table ISO 8859-15 est donc compatible avec la table ASCII et permet de décoder sans erreur des textes encodés préalablement avec la table ASCII.
Mais comment font les Grecs pour écrire leur alphabet ? Il leur suffit d'utiliser une autre table, appelée ISO-8859-7. On retrouve les caractères hérités de l'ASCII, puis des caractères spécifiques à la langue grecque...
Et les Thaïlandais alors ? Pas de problème, ils ont la ISO-8859-11 :
Que fait un logiciel à l'ouverture d'un fichier texte ? Il essaie de deviner l'encodage utilisé... Parfois cela marche, parfois non, comme le montre le problème d'affichage dans un navigateur dans l'illustration ci-dessous.
IV. Une normalisation avec l'arrivée de l'UTF8⚓︎
A savoir
En 1996, le Consortium Unicode décide de normaliser tout cela et de créer un système unique qui contiendra l'intégralité des caractères dont les êtres humains ont besoin pour communiquer entre eux.
Le consortium crée l'Universal character set Transformation Format : l'UTF. Ou plutôt ils en créent... plusieurs :
- L'UTF-8 : les caractères sont codés sur 1, 2, 3 ou 4 octets.
- L'UTF-16 : les caractères sont codés sur 2 ou 4 octets.
- L'UTF-32 : les caractères sont codés sur 4 octets
En UTF-32, 32 bits sont disponibles, soit \(2^32=4294967296\) caractères différents encodables. C'est largement suffisant, mais c'est surtout très très lourd ! D'autres encodages plus légers, mais plus complexes, sont donc proposés.
L'UTF-8 qui est de loin le plus utilisé. Le principe fondateur de l'UTF-8 est qu'il est adaptatif : les caractères les plus fréquents sont codés sur un octet, qui est la taille minimale (et qui donne le 8 de "UTF-8"). Les autres caractères peuvent être codés sur 2, 3 ou 4 octets au maximum.
Nbre d'octets | Nbre de bits pour le point de code | 1er point de code (Hexa) | Dernier point de code (Hexa) | OCTET 1 | OCTET 2 | OCTET 3 | OCTET 4 |
---|---|---|---|---|---|---|---|
1 | 7 | U+0000 | U+007F | 0xxxxxxx | |||
2 | 11 | U+0080 | U+07FF | 110xxxxx | 10xxxxxx | ||
3 | 16 | U+0800 | U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | |
4 | 21 | U+10000 | U+10FFFF | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
Tableau simplifié du codage UTF-8
Exemple⚓︎
Codage en UTF-8 du caractère « € » dont le nombre Unicode hexadécimal est U+20AC.
- Sur combien d'octets sera codé le symbole € en UTF8 ?
Solution
Pour déterminer le nombre d'octets nécessaires pour coder le caractère « € » en UTF-8, nous devons examiner sa valeur Unicode.
- Le point de code Unicode de « € » est U+20AC.
- En hexadécimal, U+20AC se situe entre U+0800 et U+FFFF.
D'après le tableau simplifié du codage UTF-8 :
Nbre d'octets | Nbre de bits pour le point de code | 1er point de code (Hexa) | Dernier point de code (Hexa) | OCTET 1 | OCTET 2 | OCTET 3 | OCTET 4 |
---|---|---|---|---|---|---|---|
1 | 7 | U+0000 | U+007F | 0xxxxxxx | |||
2 | 11 | U+0080 | U+07FF | 110xxxxx | 10xxxxxx | ||
3 | 16 | U+0800 | U+FFFF | 1110xxxx | 10xxxxxx | 10xxxxxx | |
4 | 21 | U+10000 | U+10FFFF | 11110xxx | 10xxxxxx | 10xxxxxx | 10xxxxxx |
Le caractère « € » (U+20AC) sera donc codé sur 3 octets.
- Quel est la conversion de 20AC en binaire ?
Solution
Pour convertir 20AC en binaire :
- 20AC en hexadécimal se décompose en : 2 (0010 en binaire), 0 (0000 en binaire), A (1010 en binaire), C (1100 en binaire).
- En assemblant ces valeurs, nous obtenons : 0010 0000 1010 1100.
Donc, 20AC en binaire est 0010 0000 1010 1100.
-
Pour trouver le code UTF8, on répartit les bits du code binaire sur les emplacements notés xxxxxxxx donnés dans le tableau précédent en partant de la droite et en complétant avec des zéros à gauche si nécessaire.
Trouver le code UTF8 du symbole €.
Solution
Pour trouver le code UTF-8 du symbole « € », nous devons répartir les bits du code binaire sur les emplacements notés xxxxxxxx donnés dans le tableau précédent en partant de la droite et en complétant avec des zéros à gauche si nécessaire.
Le code binaire de 20AC est 0010 0000 1010 1100.
En UTF-8, pour un codage sur 3 octets, la structure est la suivante :
- Premier octet : 1110xxxx
- Deuxième octet : 10xxxxxx
- Troisième octet : 10xxxxxx
Répartissons les bits a la place des x:
- Premier octet : 1110 (préfixe) + 0010 (4 premiers bits 0010 0000 1010 1100) = 11100010
- Deuxième octet : 10 (préfixe) + 000010 (6 bits suivants 0010 0000 1010 1100) = 10000010
- Troisième octet : 10 (préfixe) + 101100 (6 bits restants 0010 0000 1010 1100) = 10101100
Donc, le code UTF-8 binaire du symbole « € » est : 11100010 10000010 10101100
Ce qui donne en hexadécimal :
- Premier octet : 11100010 => E2 en hexadécimal
- Deuxième octet : 10000010 => 82 en hexadécimal
- Troisième octet : 10101100 => AC en hexadécimal
Le code UTF-8 hexadécimal du symbole « € » est donc E2 82 AC.
V. Caractères et chaînes de caractères en Python⚓︎
A savoir
1. Codages et décodages des caractères en Python⚓︎
Les instructions suivantes permettent convertir les différents codes associés aux caractères en Python
-
La fonction
bin()
permet d’obtenir la conversion d’un entier en binaire.print(bin(65)) >>> 0b1000001
-
La fonction
int()
renvoie le nombre décimal correspondant à la valeur binaire passée en paramètre.print(int('1000001', 2)) >>> 65
-
La fonction
chr()
renvoie le caractère correspondant à la valeur décimale passée en paramètre.print(chr(78)) >>> 'N'
-
La fonction
ord()
renvoie le point de code décimal correspondant au caractère passé en paramètreprint(ord('N') >>> 78
-
La fonction
hex()
renvoie la valeur hexadécimale correspodnant au du nombre binaire ou décimal passé en paramètre.print(hex(123)) # decimal >>> 0x7b print(hex(0b111)) # binaire >>> 0x7
A savoir
2. Les chaînes de caractères en Python⚓︎
a) Instructions pour manipuler les chaines de caractères en Python⚓︎
Les chaînes de caractères (type str
en Python) sont des types de variables qui permettent d'écrire du texte (espaces, symboles, alphanumériques...):elles sont définies en utilisant des guillemets simples '
(apostrophe) ou doubles "
.
Une chaîne de caractères n'est pas modifiable, elle est immuable.
Exemples:
nom = 'Albert'
message = "Salut, comment vas tu?"
Pour créer une chaîne vide, il suffit d'écrire deux aspostrophes ou deux guillemets de suite : ceci est très utile pour initialiser une nouvelle chaîne:
Exemples:
chaine_vide_1 = ' '
chaine_vide_2 = " "
Quelques fonctions possible sur les chaines de caractère:
-
Le typage ou comment transformer un nombre en chaine de caractères :
str
a = 12 mot = str(a) print(mot, type(mot)) >>> 12 <class 'str'>
-
La longueur ou le nombre de caractères :
len
print(len("abc")) >>> 3
-
La concaténation, la mise bout à bout de deux chaînes :
+
message = "Sa" + "lut" print(message) >>> Salut
-
La répétition :
* entier
message = "Bon " * 3 print(message) >>> Bon Bon Bon
-
L'appartenance :
in
print("py" in "Python") >>> True #Vrai print("Ah" in "Python") >>> False #Faux
b) Indexation et aprcours des chaînes de caractère en Python⚓︎
L'indexation est la numérotation de la place de chaque caractère dans la chaine de caractères : cette numérotation commence à 0 et finit à longueur - 1.
Exemple : la chaine ci-dessous comprend 6 caractères numérotés de 0 à 5.
Chaîne | p | y | t | h | o | n |
---|---|---|---|---|---|---|
Index ou Indice | 0 | 1 | 2 | 3 | 4 | 5 |
Ainsi, le premier caractère p
est numéroté 0
, le deuxième y
est numéroté 1
, ... et le sixième n
est numéroté 5
.
Pour accéder à un caractère en aprticulier on utilise la notation nom_chaine[index]
dans lequel index
est un entier indiquant la position :
chaine = "Alligator"
print(chaine[0])
>>> A
print(chaine[3])
>>> i
print(chaine(len(chaine) - 1)
>>> r
L'indexation permet de parcourir les chaine à l'aide d'une boucle for
:
chaine = "Alligator"
for i in range(len(chaine)):
print(chaine[i])
>>> A
>>> l
>>> l
>>> i
>>> g
>>> a
>>> t
>>> o
>>> r
On peut remplacer le code print(chaine[i])
par n'importe quel traitement du caractère (transformation majuscule-minuscule, code binaire, hexadécimal ....)
chaine = "Alligator"
for i in range(len(chaine)):
print(ord(chaine[i]))
>>> 65
>>> 108
>>> 108
>>> 105
>>> 103
>>> 97
>>> 116
>>> 111
>>> 114
Références