25 - Encodage des textes
Prérequis : Cette activité s'effectue normalement après avoir effectué celle de la partie Donnée sur l'intérêt de l'hexadécimal. Vous devez donc normalement comprendre le principe de l'ASCII et savoir exprimer un nombre en base 10 (décimal) ou en base 16 (hexadécimal).
Après cette activité, vous comprendrez les blagues de ce style :

Logiciel nécessaire pour l'activité : Python 3 : Thonny, IDLE ...
Evaluation ✎ : questions 04-05-06-09-10-11-13-18-20
1 - ASCII
Nous avons vu que les ordinateurs stockent uniquement des bits associés en octets :
- un nombre entier est représenté par un ou plusieurs octets
- un nombre à virgule est représenté par une suite d'octets
- une image est représentée par une suite d'octets,
- un texte est représenté par une suite d'octets.
On a donc besoin d'une table de conversion lorsqu'on veut écrire un texte ou qu'on veut le lire . Sans la technique de conversion, impossible de savoir les nombres qu'il faut écrire à la place du texte initial ou comment décoder les nombres qu'on est en train de lire !
La transformation caractère en nombre est ce qu'on nomme l'encodage.
La transformation nombre vers caractère est ce qu'on nomme le décodage.
Initialement, la mémoire des ordinateurs n'était pas très grande et les communications n'étaient pas très fiables.
La première table normalisée partagée à grande échelle est la table ASCII : American Standard Code for Information Interchange.
Principe de la table ASCII
Apparue dans les années 1960, la table ASCII est devenue le standard incontournable des 128 premiers caractères.
Elle est publiée pour la première fois en 1963 et est le résultat d'un groupe de travail. La table ASCII attribue des valeurs codifiées
- à 32 caractères dits caractères de contrôle : passage à la ligne, acquittement (voir la partie TCP), début de fichier, fin de fichier...
- aux lettres minuscules (a-z),
- majuscules (A-F),
- aux chiffres décimaux (0-9),
- aux caractères de ponctuation,
- à quelques symboles mathématiques ou non...
Jusqu'alors, chaque matériel avait sa propre table d'encodage/décodage... Changer de support impliquait donc de changer les codes à inscrire !
La taille choisie pour l'encodage des caractères était de 7 bits. On pouvait donc encoder 27, soit 128 caractères au total. Pas un de plus. Cela représentait une place mémoire non négligeable à l'époque : on était à quelques centaines de kilo-octets (ko) à l'époque. De quoi encoder un petit livre uniquement, ou une image de qualité très médiocre.
Un petit bout de la table ASCII
Caractère encodé | En binaire (7 bits) | En décimal | En hexadécimal |
---|---|---|---|
A | 100 0001 |
65 | 41 |
B | 100 0010 |
66 | 42 |
C | 100 0011 |
67 | 43 |
Sous cette forme de tableau avec une ligne par caractère, cela va donner 128 lignes. Cette représentation prendrait beaucoup de place.
On préfère représenter la correspondance Code/Caractère via un tableau à deux entrées.
Quelques alias du nom ASCII :
- iso-ir-6
- ANSI_X3.4-1968
- ANSI_X3.4-1986
- ISO_646.irv:1991
- ISO646-US
- US-ASCII
- us
- IBM367
- cp367
- csASCII
Les premières questions vous permettront de remettre vos connaissances sur les bases 2 et 12 à jour.
01° Montrer que 41 12 correspond bien à 65 10.
Montrer ensuite que 100 0001
correspond également à 65 10.
...CORRECTION...
Calculons la valeur du nombre en base 10.
41
12
= (4 * 16 + 1)
10
= (64 + 1)
10
= 65
10
On peut faire la même chose avec le binaire.
100 0001
2
= (1 * 64 + 1 * 1)
10
= 65
10
02° En décomposant 0100 0001
en deux quartets, montrer que ce nombre s'écrit bien 41 12.
...CORRECTION...
100 0001
peut s'écrire 0100
et 0001
On voit immédiatement que le premier quartet correspond à 4 et le deuxième à 1.
Les communications n'étant pas très fiables à l'époque, le 8e bit servait de bit de contrôle lors des communications : un exemple possible à l'émission,
- si le code du caractère comporte un nombre pair de bits à 1, on met le 8e à 0 : on a au total un nombre pair de bits à 1,
- si le code du caractère comporte un nombre impair de bits à 1, on met le 8e à 1 : on a au total un nombre pair de bits à 1,
Voici ce qu'on devrait envoyer pour émettre un A, un B ou un C.
Caractère encodé | En binaire (7 bits) | Nombre de bits à 1 |
---|---|---|
A | 0100 0001 |
2 donc pair |
B | 0100 0010 |
2 donc pair |
C | 1100 0011 |
4 donc pair |
L'ordinateur récepteur pouvait alors faire la même chose sur les 7 bits. En comparant à la valeur du 8e bit, on pouvait savoir si une erreur de transmission avait à priori eu lieu.
03° Expliquer si les codes de caractères ci-dessous, reçus par un ordinateur sont possiblement erronés.
1100 0111
1100 1111
...CORRECTION...
Le premier est invalide : il y 5 bits à 1. Une erreur de transmission est détéctée.
Le deuxième comporte 6 bits à 1. Un nombre pair. Soit la communication est bonne, soit il y a eu plusieurs erreurs en même temps !
Voici la table ASCII complète, en version hexadécimale. Vous pouvez visualiser la valeur décimale d'un caractère en stabilisant la souris au dessus du caractère.
Table ASCII en version hexadécimale
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0_ | NUL | SOH | STX | ETX | EOT | ENQ | ACK | BEL | BS | HT | LF | VT | FF | CR | SO | SI | _0 |
1_ | DLE | DC1 | DC2 | DC3 | DC4 | NAK | SYN | ETB | CAN | EM | SUB | ESC | FS | GS | RS | US | 1_ |
2_ | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | 2_ | |
3_ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? | 3_ |
4_ | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | 4_ |
5_ | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ | 5_ |
6_ | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | 6_ |
7_ | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | DEL | 7_ |
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F |
✎ 04° Utiliser le tableau pour trouver le caractère qui correspond à la valeur 0A 16.
Avec quelle association de caractères d'échappement parvient-on à le symboliser en Python ?
\t
?\n
?\f
?
2 - Encodage et décodage avec Python
Voyons maintenant comment Python parvient à gérer ces histoires d'encodage.
Méthode des strings : encode
On peut créer une suite d'octets en Python en utilisant la méthode encode. Cette méthode attend au moins un string contenant le nom de l'encodage à utiliser en argument.
La méthode renvoie un objet de type bytes qui veut dire usuellement octets.
>>> octets = "ABCDE".encode('ascii')
>>> type(octets)
<class 'bytes'>
Python affiche ces objets comme des strings précédés d'un b minuscule.
>>> print(octets)
b'ABCDE'
Si la valeur de l'octet correspond à un caractère ASCII imprimable, l'interpréteur va alors afficher le caractère plutôt que la valeur.
Pour voir qu'il s'agit bien d'octets (0 à 255), il faut les afficher un par un ou les transformer en tableau (nous utilisons l'objet list en Python).
Remarque : il faut appuyer deux fois sur ENTREE pour lancer la boucle FOR.
>>> tableau = list(octets)
>>> tableau
[65, 66, 67, 68, 69]
>>> for octet in octets : print(octet)
65
66
67
68
69
✎ 05° Utiliser les instructions ci-dessous dans votre Shell. Répondre ensuite aux questions :
>>> octets = "AB\nCD".encode('ascii')
>>> octets
b'AB\nCD'
>>> len(octets)
5
>>> list(octets)
[65, 66, 10, 67, 68]
Questions :
- Que représente
\n
? - Par quel octet est-il encodé ?
- Pourquoi le string
'ABC\nD'
est-il alors encodé par 5 octets alors qu'on voit clairement 6 caractères ?
✎ 06° Utiliser Python (ou à la main, mais ça va être long) pour trouver la façon dont on encode la chaîne de caractères suivante qui ne comporte aucun accent :"Bonjour a tous, l'ASCII permet d'encoder beaucoup de caracteres mais pas tous : il s'agit d'un encodage cree par les americains et donc beaucoup de caracteres des langages europeens ou asiatiques ne sont absolument pas presents dans cette table. C'est pour cela que je vous demande de ne pas mettre d'accents dans les noms de variables en Python, meme si nous verrons que le langage Python sait les gerer. Mais ce n'est pas le cas de tous les langages de programmation."
Question supplémentaire : combien d'octets sont nécessaires en mémoire pour stocker ce texte en ASCII ? Pensez à utiliser la fonction native len : elle fonctionne aussi sur les objets bytes.
Essayons maintenant de faire la même chose mais avec un texte réel. Un texte avec des accents et autres caractères étranges pour un lecteur anglais ou américain.
>>> a = "Bonjour à tous, l'ASCII permet d'encoder beaucoup de caractères mais pas tous : il s'agit d'un encodage créé par les américains et donc beaucoup de caractères des langages européens ou asiatiques ne sont absolument pas présents dans cette table. C'est pour cela que je vous demande de ne pas mettre d'accents dans les noms de variables en Python, même si nous verrons que le langage Python sait les gérer. Mais ce n'est pas le cas de tous les langages de programmation."
Là, aucun problème. Python sait très bien géré les accents dans les chaînes de caractères. Nous verrons d'ailleurs pourquoi aujourd'hui. Passons à la suite : la création de la suite d'octets encodant en ASCII ce texte :
>>> b = a.encode('ascii')
UnicodeEncodeError: 'ascii' codec can't encode character '\xe0' in position 8: ordinal not in range(128)
Et voilà : un beau message d'erreur. Visiblement le caractère d'index 8 pose problème.
>>> a[8]
'à'
Pourquoi ce caractère pose-t-il problème : simplement car il n'est pas dans la table ASCII. On aura donc du mal à trouver la valeur de l'octet à lui faire correspondre !
Avec la rapide augmentation des mémoires, l'encodage des caractères est passé de 7 bits à 8 bits.
Un bit en plus veut alors dire qu'on double le nombre de caractères disponibles : on est passé de 27 (128, de 0 à 127) à 28 (256, de 0 à 255) valeurs disponibles. Soit 128 nouvelles valeurs permettant d'encoder 128 nouveaux caractères.
Une révolution.
3 - Les tables ASCII étendues
Les tables cp sont les tables d'encodage "code page" créés par IBM sur les premiers ordinateurs personnels.
Pendant très lontemps, l'une des plus connue a été la page de code 437 utilisé par IBM pour le système DOS et ces consoles.
Voici les caractères 128 (en hexa 80 12) à 255 (en haxa FF 12) de cette table. La première partie n'est pas reproduite car ce sont les mêmes codes que l'ASCII. Le but étant d'être compatible sur les caractères 127 et moins.
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x8_ | Ç | ü | é | â | ä | à | å | ç | ê | ë | è | ï | î | ì | Ä | Å | 0x8_ |
0x9_ | É | æ | Æ | ô | ö | ò | û | ù | ÿ | Ö | Ü | ¢ | £ | ¥ | ₧ | ƒ | 0x9_ |
0xA_ | á | í | ó | ú | ñ | Ñ | ª | º | ¿ | ⌐ | ¬ | ½ | ¼ | ¡ | « | » | 0xA_ |
0xB_ | ░ | ▒ | ▓ | │ | ┤ | ╡ | ╢ | ╖ | ╕ | ╣ | ║ | ╗ | ╝ | ╜ | ╛ | ┐ | 0xB_ |
0xC_ | └ | ┴ | ┬ | ├ | ─ | ┼ | ╞ | ╟ | ╚ | ╔ | ╩ | ╦ | ╠ | ═ | ╬ | ╧ | 0xC_ |
0xD_ | ╨ | ╤ | ╥ | ╙ | ╘ | ╒ | ╓ | ╫ | ╪ | ┘ | ┌ | █ | ▄ | ▌ | ▐ | ▀ | 0xD_ |
0xE_ | α | ß | Γ | π | Σ | σ | µ | τ | Φ | Θ | Ω | δ | ∞ | φ | ε | ∩ | 0xE_ |
0xF_ | ≡ | ± | ≥ | ≤ | ⌠ | ⌡ | ÷ | ≈ | ° | ∙ | · | √ | ⁿ | ² | ■ | ¤¤¤ | 0xF_ |
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F |
Vous pourriez vous demander pourquoi ils ont placé autant de caractères graphiques ? Simplement car à l'époque les affichages étaient encore très basiques. Pas d'environnement graphique. Ces caractères permettaient de réaliser de jolis tableaux.
Ces tables ont permis de donner encore plus de créativité aux gens qui réalisaient (et réalisent encore) une forme d'art : l'ASCII-Art.
_________________________________________________
| _ _ ____ ____ ___ ___ |
| __ _ _ __| |_ / \ / ___| / ___|_ _|_ _| |
| / _` | '__| __| / _ \ \___ \| | | | | | |
| | (_| | | | |_ / ___ \ ___) | |___ | | | | |
| \__,_|_| \__|/_/ \_\____/ \____|___|___| |
|_______________________________________________|
))
\||/ ((
| @@___oo))
/\ /\ / (__,,,,|
) /^\) ^\/ _)
) /^\/ _)
) _ / / _)
/\ )/\/ || | )_)
< > |(,,) )__)
|| / \)___)\
| \____( )___) )___
\______(_______;;; __;;;
\|/(_)_(_)\|/
@~ (o.o) ~@
/___( * )___\ NA NA
/ `U' \ NANA
( . ) NA !!!
`>---<'
_\ /_
o
_====| o
====|_====|
_====| | ====| I-I-I-I-I _ _ _ _ _ _
_ _ _ _ _ _ ====| | | \ ` ' / I-I-I-I-I-I
I-I-I-I-I-I | | | |. | \ ` '_/
\ ` '_/ | / \ | | /^\| |__ [],|
[*] __| ^ / ^ \ ^ | [*]| _|______|_
|__ ,| / \ / `\ / \ | ===| <=-=-==-=-=>
___| ___ |__ / /=_=_=_=\ \ |, _| \__ _'_/
I_I__I_I__I_I (====(_________)___) |____| ___ |. _ |
\-\--|-|--/-/ | | [*I__| I_I__I____I_I_I | _ |
|[] '| | | __ . | \-\--|-|--/-/ |` '|
|. ' | __| ___ |__ ___ |__ |---------| | [] |
/ \ [] .|_| |_| |_| |_| |_| |_| [] [] | | ` |
(===) .|-=-=-=-=-=-=-=-=-=-=-| / \ |[] |
| []|` [] | . . . . . . . . . |- (===) |` __|
| []| ` |/////////\\\\\\\\\\ |__. |[] | /| |
<===> ' ||||| |||| | [] <===>-I-I-I-I-I-I-I-I-| ` I-|
\I/ 1-- ||||| Maze's |||| | . ' \i/ . | | _|
| . _||||| FunHouse |||| | | ----' |` .|
../|',v,.,,,.|||||/_________\||||,/|.,,.Y,,..|\__
Pour pouvoir afficher correctement ces dessins sur d'autres supports, il faut impérativement utiliser des polices de caractères à chasse fixe, c'est à dire que chaque caractère doit avoir exactement la même largeur.
Sinon, l'image est déformée.
Les logiciels permettant d'éditer du code sont habituellement à chasse fixe.
07° Pour voir les encodages disponibles sur votre machine, vous pouvez lancer le code suivant.
1
2
3
4
5
6
7
8
9
10
11
12 | import encodings
def lister_les_encodages():
'''Fonction qui renvoie un tableau contenant les encodages disponibles'''
les_encodages = [e for e in sorted(set(encodings.aliases.aliases.values()))]
return les_encodages
if __name__ == '__main__' :
print('Liste des encodages disponibles')
for element in lister_les_encodages():
print(f'- {element}')
|
Ce code utilise set, un ensemble. C'est une structure différente de list. Notamment, un ensemble est conçu pour ne pas contenir plusieurs fois des éléments identiques. Vous pouvez lancer le code en remplaçant set par list : vous allez voir qu'on obtient alors plusieurs fois les mêmes noms.
Vous devriez en trouver un beau paquet. Nous allons voir pourquoi il y en a autant...
A titre d'exemple, voici la liste obtenue avec sur mon système (en blanc : ceux dont nous allons parler aujourd'hui) :
Liste des encodages disponibles
- ascii
- base64_codec
- big5
- big5hkscs
- bz2_codec
- cp037
- cp1026
- cp1125
- cp1140
- cp1250
- cp1251
- cp1252
- cp1253
- cp1254
- cp1255
- cp1256
- cp1257
- cp1258
- cp273
- cp424
- cp437
- cp500
- cp775
- cp850
- cp852
- cp855
- cp857
- cp858
- cp860
- cp861
- cp862
- cp863
- cp864
- cp865
- cp866
- cp869
- cp932
- cp949
- cp950
- euc_jis_2004
- euc_jisx0213
- euc_jp
- euc_kr
- gb18030
- gb2312
- gbk
- hex_codec
- hp_roman8
- hz
- iso2022_jp
- iso2022_jp_1
- iso2022_jp_2
- iso2022_jp_2004
- iso2022_jp_3
- iso2022_jp_ext
- iso2022_kr
- iso8859_10
- iso8859_11
- iso8859_13
- iso8859_14
- iso8859_15
- iso8859_16
- iso8859_2
- iso8859_3
- iso8859_4
- iso8859_5
- iso8859_6
- iso8859_7
- iso8859_8
- iso8859_9
- johab
- koi8_r
- kz1048
- latin_1
- mac_cyrillic
- mac_greek
- mac_iceland
- mac_latin2
- mac_roman
- mac_turkish
- mbcs
- ptcp154
- quopri_codec
- rot_13
- shift_jis
- shift_jis_2004
- shift_jisx0213
- tactis
- tis_620
- utf_16
- utf_16_be
- utf_16_le
- utf_32
- utf_32_be
- utf_32_le
- utf_7
- utf_8
- uu_codec
- zlib_codec
08° Lancer maintenant le code suivant qui vous donnera la façon d'encoder les caractères accentués en utilisant la table cp437.
1
2
3
4
5
6
7
8
9
10
11
12
13 | texte = "Test avec é, des à et des è"
octets = texte.encode('cp437')
print('\nLe string de base')
print(texte)
print("\nLa suite d'octets")
print(octets)
print("\nLa suite d'octets sous forme de liste")
for octet in octets :
print(octet, end=' ')
|
Questions
- En comparant les trois affichages, trouver l'encodage en hexadécimal et décimal des é avec cp437.
- Idem pour le à
- Idem pour le è
...CORRECTION...
Si votre code ne parvient pas à se lancer pour une raison ou une autre, voici le résultat de l'affichage :
Le string de base
Test avec é, des à et des è
La suite d'octets
b'Test avec \x82, des \x85 et des \x8a'
La suite d'octets sous forme de liste
84 101 115 116 32 97 118 101 99 32 130 44 32 100
101 115 32 133 32 101 116 32 100 101 115 32 138
Pour rappel, voici la première ligne de la table cp437 avec les caractères voulus en rouge.
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x8_ | Ç | ü | é | â | ä | à | å | ç | ê | ë | è | ï | î | ì | Ä | Å | 0x8_ |
On voit donc que la façon étrange d'afficher les objets bytes a en réalité une raison d'être : on voit rapidement les caractères qui ne sont pas présents dans la table ASCII (les caractères de 0 à 127).
Le string de base
Test avec é, des à et des è
La suite d'octets
b'Test avec \x82, des \x85 et des \x8a'
La présence de l'antislash suivi du x \x
veut donc dire qu'il s'agit d'un code hexadécimal d'un caractère non-ASCII. Les valeurs sont donc supérieures ou égales à 128 en base 10 ou 80 en base 16.
On peut voir également les caractères non-ASCII dans le deuxième cas : il suffit de chercher les valeurs supérieures à 127.
Le string de base
Test avec é, des à et des è
La suite d'octets sous forme de liste
84 101 115 116 32 97 118 101 99 32 130 44 32 100
101 115 32 133 32 101 116 32 100 101 115 32 138
Si on résume dans une table :
Caractère encodé | En binaire (8 bits) | En décimal | En hexadécimal |
---|---|---|---|
é | 1000 0010 |
130 | 82 |
à | 1000 0101 |
133 | 85 |
é | 1000 1010 |
138 | 8a |
Pendant longtemps, il y a donc eu une multitude de tables : des tables pour ceux qui voulaient plutôt des caractères graphiques, des tables pour les pays d'Europe de l'Ouest, des tables pour les pays d'Europe du Nord, des tables pour le cyrillique, des tables pour les caractères asiatiques spécifiques, et même des tables par constructeurs ou par systèmes d'exploitation !
Bref, il n'était pas toujours facile de parvenir à décoder correctement un texte si on ne connaissait pas l'encodage qui avait été utilisé.
Table latin-1
L'une des autres tables très utilisée en Europe est la table iso8859_1, de son petit nom latin-1.
Elle a été l'encodage par défaut pendant de nombreuses années, sans être un standard contrairement à ASCII. Malgré ce status non-officiel, cette table a été la base pour créer UNICODE.
Elle comporte tous les caractères usuels pour écrire un texte dans l'une des langues de l'Europe de l'Ouest et reste entièrement compatible avec l'ASCII sur les caractères de valeurs inférieures à 128.
Remarquez bien qu'elle n'inclut pas de caractères graphiques : les applications graphiques sont apparues. Plus besoin de réaliser de tableaux ou de dessins sur la console en utilisant des caractères, on utilisait déjà à cette époque de vraies images par exemple.
Encore une fois, je ne mets pas les caractères 127 et moins : ce sont les mêmes valeurs que la table ASCII, de façon à garder une retro-compatibilité.
Remarquez bien que certaines valeurs ne sont pas utilisées. Certaines sont des caractères de contrôle.
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x8_ | PAD | HOP | BPH | NBH | IND | NEL | SSA | ESA | HTS | HTJ | LTS | PLD | PLU | RI | SS2 | SS3 | 0x8_ |
0x9_ | DCS | PU1 | PU2 | STS | CCH | MW | SPA | EPA | SOS | SGCI | SCI | CSI | ST | OSC | PM | APC | 0x9_ |
0xA_ | NBSP | ¡ | ¢ | £ | ¤ | ¥ | ¦ | § | ¨ | © | ª | « | ¬ | SHY | ® | ¯ | 0xA_ |
0xB_ | ° | ± | ² | ³ | ´ | µ | ¶ | · | ¸ | ¹ | º | » | ¼ | ½ | ¾ | ¿ | 0xB_ |
0xC_ | À | Á | Â | Ã | Ä | Å | Æ | Ç | È | É | Ê | Ë | Ì | Í | Î | Ï | 0xC_ |
0xD_ | Ð | Ñ | Ò | Ó | Ô | Õ | Ö | × | Ø | Ù | Ú | Û | Ü | Ý | Þ | ß | 0xD_ |
0xE_ | à | á | â | ã | ä | å | æ | ç | è | é | ê | ë | ì | í | î | ï | 0xE_ |
0xF_ | ð | ñ | ò | ó | ô | õ | ö | ÷ | ø | ù | ú | û | ü | ý | þ | ÿ | 0xF_ |
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F |
Voici les alias courants de cette table :
- ISO_8859-1:1987
- ISO_8859-1
- ISO-8859-1
- iso-ir-100
- csISOLatin1
- latin1
- l1
- IBM819
- CP819
Sachez que j'ai parlé ici de la table validée par l'IANA (Internet_Assigned_Numbers_Authority). Il existe également une version de cette table sans les caractères de contrôle.
✎ 09° Trois questions.
- 1 - En vous inspirant des codes précédents, fournir les octets permettant d'encoder ce texte en latin-1 puis en utilisant cp437.
- 2 - Quel est le seul caractère dont l'encodage est différent sur les deux tables ici ?
- 3 - Conclure sur les problèmes que peut provoquer la non-connaissance de l'encodage utilisé à la création pour ouvrir un fichier texte en lecture.
Le texte : "Perceval ne sait vraiment pas écrire en latin !"
.
Pensez à alors voir votre liste d'encodages obtenue à la question 07 si votre programme dit qu'il ne connait pas l'un de ces encodages.
Je n'ai présenté ici qu'une toute petite partie des tables d'encodage qui étaient (et sont encore) disponibles. Plus d'exemple dans la fiche présentée en fin d'activité.
Sachez néanmoins que la table latin-1 a connu une mise à jour importante pour l'Europe : la table latin-9 (également nommée iso8859_15, et oui, c'est pas le même numéro...) inclut en effet un caractère qui n'existait pas au moment de la création de la première : le signe de l'Euro, la monnaie.
Latin-9, une sorte de mise à jour de latin-1
En rose, les associations valeurs-caractères qui ont changé par rapport à latin-1.
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x8_ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | 0x8_ |
0x9_ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | 0x9_ |
0xA_ | ¤¤¤ | ¡ | ¢ | £ | € | ¥ | Š | § | š | © | ª | « | ¬ | ¤¤¤ | ® | ¯ | 0xA_ |
0xB_ | ° | ± | ² | ³ | Ž | µ | ¶ | · | ž | ¹ | º | » | Œ | œ | Ÿ | ¿ | 0xB_ |
0xC_ | À | Á | Â | Ã | Ä | Å | Æ | Ç | È | É | Ê | Ë | Ì | Í | Î | Ï | 0xC_ |
0xD_ | Ð | Ñ | Ò | Ó | Ô | Õ | Ö | × | Ø | Ù | Ú | Û | Ü | Ý | Þ | ß | 0xD_ |
0xE_ | à | á | â | ã | ä | å | æ | ç | è | é | ê | ë | ì | í | î | ï | 0xE_ |
0xF_ | ð | ñ | ò | ó | ô | õ | ö | ÷ | ø | ù | ú | û | ü | ý | þ | ÿ | 0xF_ |
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F |
Un dernier exemple pour la route, l'iso-8859-11 ou Thai. Les 128 premières valeurs sont celles de l'ASCII, c'est à partir de 128 que ça diffère. Il y a même 8 valeurs non utilisées.
...iso-8859-11...
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x8_ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | 0x8_ |
0x9_ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | 0x9_ |
0xA_ | ¤¤¤ | ก | ข | ฃ | ค | ฅ | ฆ | ง | จ | ฉ | ช | ซ | ฌ | ญ | ฎ | ฏ | 0xA_ |
0xB_ | ฐ | ฑ | ฒ | ณ | ด | ต | ถ | ท | ธ | น | บ | ป | ผ | ฝ | พ | ฟ | 0xB_ |
0xC_ | ภ | ม | ย | ร | ฤ | ล | ฦ | ว | ศ | ษ | ส | ห | ฬ | อ | ฮ | ฯ | 0xC_ |
0xD_ | ะ | ั | า | ำ | ิ | ี | ึ | ื | ุ | ู | ฺ | � | � | � | � | ฿ | 0xD_ |
0xE_ | เ | แ | โ | ใ | ไ | ๅ | ๆ | ็ | ่ | ้ | ๊ | ๋ | ์ | ํ | ๎ | ๏ | 0xE_ |
0xF_ | ๐ | ๑ | ๒ | ๓ | ๔ | ๕ | ๖ | ๗ | ๘ | ๙ | ๚ | ๛ | � | � | � | � | 0xF_ |
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F |
Si on résume, il existe une multitude de tables d'encodages sur un octet permettant d'écrire dans toutes les langues.
Pourquoi "encodages sur un octet" ? Tout simplement car toutes ces tables contiennent 256 associations valeurs-caractères qui permettent d'encoder un texte en prenant exactement 1 octet par caractère.
En réalité, toutes ces tables ne différent la plupart du temps que sur les valeurs 128 et plus. Elles gardent un compatibilité quasi-totale avec ASCII et proposent 128 caractères différents ensuite.
On notera d'ailleurs que l'espace est un caractère qui possède une valeur (32 10 ou 20 16) et nécessite donc un octet en mémoire.
Idem pour le passage à la ligne : le fameux caractère de contrôle qui j'avais représenté par une sorte de flèche-rouge ↲
lors de la partie sur la description des requêtes GET / POST :
GET /act/archi/communication-client-serveur/ HTTP/1.1↲
Host: www.infoforall.fr↲
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0↲
Il s'agit du caractère LF, LINE FEED, \n
dans les strings de Python. Il possède une valeur 10 10 ou 0A 16. Et il représente un octet à chaque fois qu'il est présent. Comme n'importe quel autre caractère.
Vous pouvez être quasiment certain de ces deux valeurs d'octets lorsque vous les rencontrez dans un fichier-texte.
✎ 10° Estimer la taille en octet nécessaire pour encoder ce texte en latin-1. Pensez bien à tous les caractères, même les caractères "cachés".
Bon, alors
combien d'octets pour
stocker
ça ?
Avec ce principe, on peut donc écrire un texte en anglais, un texte en français (en prenant une table contenant les caractères voulus), un texte en chinois (en prenant une table contenant les bons caractères), un texte en russe (en prenant une table contenant les bons caractères)...
Deux problèmes néanmoins qui vont justifier l'invention d'UNICODE :
- Si on ne connait pas la table ayant réalisé le codage, difficile de parvenir à faire le décodage vu le nombre de tables disponibles...
- Si on veut écrire un texte dans plusieurs langues sur un même support (comme un site Web), ben, c'est pas possible...
4 - Encodage et décodage
Nous avons vu comment encoder avec la méthode encode. Il est temps de parvenir à savoir décoder avec la méthode ... decode.
Méthode des bytes : decode
On peut créer un string en utilisant sur un objet bytes la méthode decode. Cette méthode attend au moins un string contenant le nom de la table d'encodage à utiliser en argument.
La méthode renvoie un objet de type str.
Un exemple avec un texte qu'on avait encodé en latin-9, nommé plutôt iso8859_15 sur ma machine. Voir la question 07 pour voir le nom qu'elle peut porter sur la votre.
>>> texte = b"Cet article co\xFBte\x2020\xA3.".decode('iso8859_15')
>>> texte
'Cet article coûte 20£.'
Pourquoi un tel résultat ? Il suffit d'aller voir la valeur des caractères en hexadécimal pour ceux précédé de \x.
\xFB
pourû
.\x20
pour\xA3
pour£
.
✎ 11° Que va contenir texte dans l'exemple ci-dessous ?
Attention, il y a une différence par rapport à l'exemple du dessus.
>>> texte = b"Cet article co\xFBte\x2020\xA4.".decode('iso8859_15')
>>> texte
? votre réponse ?
Là où c'était vraiment pénible, c'était donc lorsqu'on ne connaissait pas l'encode d'un texte. On devait faire au hasard, en utilisant l'encodage le plus probable.
Voici ainsi un exemple où on encode un texte en utilisant une table d'encodage précise et où on tente de décoder ce même texte en utilisant des tables au hasard...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | texte = "Ce n'est pas facile, et même plutôt compliqué de décoder une table contenant des caractères étranges, ou des valeurs comment des $, des £ ou des €."
octets = texte.encode('iso8859_15')
# La suite brute des octets
for octet in octets :
print(octet, end=" ")
# Tentative d'ouverture en latin-1
print('\nEn utilisant latin-1')
print(octets.decode('latin-1'))
# Tentative d'ouverture en iso8859_2 (Europe centrale)
print('\nEn utilisant iso8859_2')
print(octets.decode('iso8859_2'))
# Tentative d'ouverture en iso8859_3 (Europe du Sud)
print('\nEn utilisant iso8859_3')
|
Et voici les réponses fournies par Python :
67 101 32 110 39 101 115 116 32 112 97 115 32 102 97 99 105 108 101 44 32 101 116 32 109 234 109 101 32 112 108 117 116 244 116 32 99 111 109 112 108 105 113 117 233 32 100 101 32 100 233 99 111 100 101 114 32 117 110 101 32 116 97 98 108 101 32 99 111 110 116 101 110 97 110 116 32 100 101 115 32 99 97 114 97 99 116 232 114 101 115 32 233 116 114 97 110 103 101 115 44 32 111 117 32 100 101 115 32 118 97 108 101 117 114 115 32 99 111 109 109 101 110 116 32 100 101 115 32 36 44 32 100 101 115 32 163 32 111 117 32 100 101 115 32 164 46
En utilisant latin-1
Ce n'est pas facile, et même plutôt compliqué de décoder une table contenant
des caractères étranges, ou des valeurs comment des $, des £ ou des ¤.
En utilisant iso8859_2
Ce n'est pas facile, et męme plutôt compliqué de décoder une table contenant
des caractčres étranges, ou des valeurs comment des $, des Ł ou des ¤.
En utilisant iso8859_3
Ce n'est pas facile, et même plutôt compliqué de décoder une table contenant
des caractères étranges, ou des valeurs comment des $, des £ ou des ¤.
En utilisant iso8859_11
Ce n'est pas facile, et m๊me plut๔t compliqu้de d้coder une table contenant
des caract่res ้tranges, ou des valeurs comment des $, des ฃ ou des ค.
Comme on le voit, parfois ça marche, parfois certains caractères ne sont pas les bons. Bref, ce n'est pas possible en tant qu'outil professionnel d'édition.
D'où l'invention d'un nouveau système plus flexible que des tables de 256 caractères.
5 - UNICODE
Tant que les ordinateurs ne communiquaient pas entre eux, ou qu'ils le faisaient dans la même langue, cela ne posait pas (trop) de problème. Mais avec l'apparition de la communication globale via Internet, un langage de programmation pouvait fonctionner avec un certain encodage à l'interne (par exemple cp1252) et créer un fichier-texte encodé en latin-3. Ensuite, ce fichier pouvait être lu en Turquie par quelqu'un ayant un encodage de type mac-turkish. Bref, les risques d'avoir des affichages bizarres (au mieux), des programmes qui plantent ou des bases de données complétement anéanties (le pire qui soit) devenait non négligeable.
UNICODE
UNICODE n'est pas une table d'encodage à proprement parler.
Il s'agit juste d'une correspondance entre :
- Un numéro unique attribué au caractère
- Le glyphe du caractère
- Le nom descriptif du caractère
A la charge de système d'encodage adapté de faire la correspondance. UNICODE ne se charge pas de la technique. C'est uniquement une correspondance entre un numéro et un caractère.
Les encodages UTF-8, UTF-16, UTF-32 se chargent de l'aspect technique justement.

Actuellement, UNICODE est une vaste collection qui contient tous les caractères des langues connues, les caractères scientifiques, des éléments graphiques mais également des icones comme les emote-icons.
Pour maintenir une retro-compatibilité, les valeurs UNICODE des valeurs 0 à 255 correspondent exactement aux valeurs décimales de la table d'encodage sur un octet latin-1. Cela veut dire également que les valeurs 0 à 127 correspondent exactement aux valeurs décimales de la table ASCII.
Les caractères présents sur les autres tables d'un octet sont présents dans UNICODE mais à des valeurs supérieures à 256.
Plus de renseignements et une visualisation de tous les caractères, sur le site d'UNICIDE.
La page correspondante de Wikipedia est très bien réalisée également WIKIPEDIA.
Voici quelques minces extraits des caractères présents dans UNICODE. Pour visualiser le numéro en décimal, il suffit de rester stationnaire au dessus du caractère.
...0 à 255 : identique aux valeurs latin-1...
Numéros 0-255 | ||||||||||||||||
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x0_ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ |
0x1_ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ |
0x2_ | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | |
0x3_ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
0x4_ | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
0x5_ | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
0x6_ | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
0x7_ | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ | ¤¤¤ |
0x8_ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ |
0x9_ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ | ¤¤¤ |
0xA_ | ¤¤¤ | ¡ | ¢ | £ | ¤ | ¥ | ¦ | § | ¨ | © | ª | « | ¬ | ¤¤¤ | ® | ¯ |
0xB_ | ° | ± | ² | ³ | ´ | µ | ¶ | · | ¸ | ¹ | º | » | ¼ | ½ | ¾ | ¿ |
0xC_ | À | Á | Â | Ã | Ä | Å | Æ | Ç | È | É | Ê | Ë | Ì | Í | Î | Ï |
0xD_ | Ð | Ñ | Ò | Ó | Ô | Õ | Ö | × | Ø | Ù | Ú | Û | Ü | Ý | Þ | ß |
0xE_ | à | á | â | ã | ä | å | æ | ç | è | é | ê | ë | ì | í | î | ï |
0xF_ | ð | ñ | ò | ó | ô | õ | ö | ÷ | ø | ù | ú | û | ü | ý | þ | ÿ |
...Numéros 256-511...
Numéros 256-511 | ||||||||||||||||
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x10_ | Ā | ā | Ă | ă | Ą | ą | Ć | ć | Ĉ | ĉ | Ċ | ċ | Č | č | Ď | ď |
0x11_ | Đ | đ | Ē | ē | Ĕ | ĕ | Ė | ė | Ę | ę | Ě | ě | Ĝ | ĝ | Ğ | ğ |
0x12_ | Ġ | ġ | Ģ | ģ | Ĥ | ĥ | Ħ | ħ | Ĩ | ĩ | Ī | ī | Ĭ | ĭ | Į | į |
0x13_ | İ | ı | IJ | ij | Ĵ | ĵ | Ķ | ķ | ĸ | Ĺ | ĺ | Ļ | ļ | Ľ | ľ | Ŀ |
0x14_ | ŀ | Ł | ł | Ń | ń | Ņ | ņ | Ň | ň | ʼn | Ŋ | ŋ | Ō | ō | Ŏ | ŏ |
0x15_ | Ő | ő | Œ | œ | Ŕ | ŕ | Ŗ | ŗ | Ř | ř | Ś | ś | Ŝ | ŝ | Ş | ş |
0x16_ | Š | š | Ţ | ţ | Ť | ť | Ŧ | ŧ | Ũ | ũ | Ū | ū | Ŭ | ŭ | Ů | ů |
0x17_ | Ű | ű | Ų | ų | Ŵ | ŵ | Ŷ | ŷ | Ÿ | Ź | ź | Ż | ż | Ž | ž | ſ |
0x18_ | ƀ | Ɓ | Ƃ | ƃ | Ƅ | ƅ | Ɔ | Ƈ | ƈ | Ɖ | Ɗ | Ƌ | ƌ | ƍ | Ǝ | Ə |
0x19_ | Ɛ | Ƒ | ƒ | Ɠ | Ɣ | ƕ | Ɩ | Ɨ | Ƙ | ƙ | ƚ | ƛ | Ɯ | Ɲ | ƞ | Ɵ |
0x1A_ | Ơ | ơ | Ƣ | ƣ | Ƥ | ƥ | Ʀ | Ƨ | ƨ | Ʃ | ƪ | ƫ | Ƭ | ƭ | Ʈ | Ư |
0x1B_ | ư | Ʊ | Ʋ | Ƴ | ƴ | Ƶ | ƶ | Ʒ | Ƹ | ƹ | ƺ | ƻ | Ƽ | ƽ | ƾ | ƿ |
0x1C_ | ǀ | ǁ | ǂ | ǃ | DŽ | Dž | dž | LJ | Lj | lj | NJ | Nj | nj | Ǎ | ǎ | Ǐ |
0x1D_ | ǐ | Ǒ | ǒ | Ǔ | ǔ | Ǖ | ǖ | Ǘ | ǘ | Ǚ | ǚ | Ǜ | ǜ | ǝ | Ǟ | ǟ |
0x1E_ | Ǡ | ǡ | Ǣ | ǣ | Ǥ | ǥ | Ǧ | ǧ | Ǩ | ǩ | Ǫ | ǫ | Ǭ | ǭ | Ǯ | ǯ |
0x1F_ | ǰ | DZ | Dz | dz | Ǵ | ǵ | Ƕ | Ƿ | Ǹ | ǹ | Ǻ | ǻ | Ǽ | ǽ | Ǿ | ǿ |
...Numéros 512-767...
Numéros 512-767 | ||||||||||||||||
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x20_ | Ȁ | ȁ | Ȃ | ȃ | Ȅ | ȅ | Ȇ | ȇ | Ȉ | ȉ | Ȋ | ȋ | Ȍ | ȍ | Ȏ | ȏ |
0x21_ | Ȑ | ȑ | Ȓ | ȓ | Ȕ | ȕ | Ȗ | ȗ | Ș | ș | Ț | ț | Ȝ | ȝ | Ȟ | ȟ |
0x22_ | Ƞ | ȡ | Ȣ | ȣ | Ȥ | ȥ | Ȧ | ȧ | Ȩ | ȩ | Ȫ | ȫ | Ȭ | ȭ | Ȯ | ȯ |
0x23_ | Ȱ | ȱ | Ȳ | ȳ | ȴ | ȵ | ȶ | ȷ | ȸ | ȹ | Ⱥ | Ȼ | ȼ | Ƚ | Ⱦ | ȿ |
0x24_ | ɀ | Ɂ | ɂ | Ƀ | Ʉ | Ʌ | Ɇ | ɇ | Ɉ | ɉ | Ɋ | ɋ | Ɍ | ɍ | Ɏ | ɏ |
0x25_ | ɐ | ɑ | ɒ | ɓ | ɔ | ɕ | ɖ | ɗ | ɘ | ə | ɚ | ɛ | ɜ | ɝ | ɞ | ɟ |
0x26_ | ɠ | ɡ | ɢ | ɣ | ɤ | ɥ | ɦ | ɧ | ɨ | ɩ | ɪ | ɫ | ɬ | ɭ | ɮ | ɯ |
0x27_ | ɰ | ɱ | ɲ | ɳ | ɴ | ɵ | ɶ | ɷ | ɸ | ɹ | ɺ | ɻ | ɼ | ɽ | ɾ | ɿ |
0x28_ | ʀ | ʁ | ʂ | ʃ | ʄ | ʅ | ʆ | ʇ | ʈ | ʉ | ʊ | ʋ | ʌ | ʍ | ʎ | ʏ |
0x29_ | ʐ | ʑ | ʒ | ʓ | ʔ | ʕ | ʖ | ʗ | ʘ | ʙ | ʚ | ʛ | ʜ | ʝ | ʞ | ʟ |
0x2A_ | ʠ | ʡ | ʢ | ʣ | ʤ | ʥ | ʦ | ʧ | ʨ | ʩ | ʪ | ʫ | ʬ | ʭ | ʮ | ʯ |
0x2B_ | ʰ | ʱ | ʲ | ʳ | ʴ | ʵ | ʶ | ʷ | ʸ | ʹ | ʺ | ʻ | ʼ | ʽ | ʾ | ʿ |
0x2C_ | ˀ | ˁ | ˂ | ˃ | ˄ | ˅ | ˆ | ˇ | ˈ | ˉ | ˊ | ˋ | ˌ | ˍ | ˎ | ˏ |
0x2D_ | ː | ˑ | ˒ | ˓ | ˔ | ˕ | ˖ | ˗ | ˘ | ˙ | ˚ | ˛ | ˜ | ˝ | ˞ | ˟ |
0x2E_ | ˠ | ˡ | ˢ | ˣ | ˤ | ˥ | ˦ | ˧ | ˨ | ˩ | ˪ | ˫ | ˬ | ˭ | ˮ | ˯ |
0x2F_ | ˰ | ˱ | ˲ | ˳ | ˴ | ˵ | ˶ | ˷ | ˸ | ˹ | ˺ | ˻ | ˼ | ˽ | ˾ | ˿ |
...Numéros 8704-8959...
Numéros 8704-8959 | ||||||||||||||||
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0x220_ | ∀ | ∁ | ∂ | ∃ | ∄ | ∅ | ∆ | ∇ | ∈ | ∉ | ∊ | ∋ | ∌ | ∍ | ∎ | ∏ |
0x221_ | ∐ | ∑ | − | ∓ | ∔ | ∕ | ∖ | ∗ | ∘ | ∙ | √ | ∛ | ∜ | ∝ | ∞ | ∟ |
0x222_ | ∠ | ∡ | ∢ | ∣ | ∤ | ∥ | ∦ | ∧ | ∨ | ∩ | ∪ | ∫ | ∬ | ∭ | ∮ | ∯ |
0x223_ | ∰ | ∱ | ∲ | ∳ | ∴ | ∵ | ∶ | ∷ | ∸ | ∹ | ∺ | ∻ | ∼ | ∽ | ∾ | ∿ |
0x224_ | ≀ | ≁ | ≂ | ≃ | ≄ | ≅ | ≆ | ≇ | ≈ | ≉ | ≊ | ≋ | ≌ | ≍ | ≎ | ≏ |
0x225_ | ≐ | ≑ | ≒ | ≓ | ≔ | ≕ | ≖ | ≗ | ≘ | ≙ | ≚ | ≛ | ≜ | ≝ | ≞ | ≟ |
0x226_ | ≠ | ≡ | ≢ | ≣ | ≤ | ≥ | ≦ | ≧ | ≨ | ≩ | ≪ | ≫ | ≬ | ≭ | ≮ | ≯ |
0x227_ | ≰ | ≱ | ≲ | ≳ | ≴ | ≵ | ≶ | ≷ | ≸ | ≹ | ≺ | ≻ | ≼ | ≽ | ≾ | ≿ |
0x228_ | ⊀ | ⊁ | ⊂ | ⊃ | ⊄ | ⊅ | ⊆ | ⊇ | ⊈ | ⊉ | ⊊ | ⊋ | ⊌ | ⊍ | ⊎ | ⊏ |
0x229_ | ⊐ | ⊑ | ⊒ | ⊓ | ⊔ | ⊕ | ⊖ | ⊗ | ⊘ | ⊙ | ⊚ | ⊛ | ⊜ | ⊝ | ⊞ | ⊟ |
0x22A_ | ⊠ | ⊡ | ⊢ | ⊣ | ⊤ | ⊥ | ⊦ | ⊧ | ⊨ | ⊩ | ⊪ | ⊫ | ⊬ | ⊭ | ⊮ | ⊯ |
0x22B_ | ⊰ | ⊱ | ⊲ | ⊳ | ⊴ | ⊵ | ⊶ | ⊷ | ⊸ | ⊹ | ⊺ | ⊻ | ⊼ | ⊽ | ⊾ | ⊿ |
0x22C_ | ⋀ | ⋁ | ⋂ | ⋃ | ⋄ | ⋅ | ⋆ | ⋇ | ⋈ | ⋉ | ⋊ | ⋋ | ⋌ | ⋍ | ⋎ | ⋏ |
0x22D_ | ⋐ | ⋑ | ⋒ | ⋓ | ⋔ | ⋕ | ⋖ | ⋗ | ⋘ | ⋙ | ⋚ | ⋛ | ⋜ | ⋝ | ⋞ | ⋟ |
0x22E_ | ⋠ | ⋡ | ⋢ | ⋣ | ⋤ | ⋥ | ⋦ | ⋧ | ⋨ | ⋩ | ⋪ | ⋫ | ⋬ | ⋭ | ⋮ | ⋯ |
0x22F_ | ⋰ | ⋱ | ⋲ | ⋳ | ⋴ | ⋵ | ⋶ | ⋷ | ⋸ | ⋹ | ⋺ | ⋻ | ⋼ | ⋽ | ⋾ | ⋿ |
...Numéros 63744-63999...
Numéros 63744-63999 | ||||||||||||||||
_0 | _1 | _2 | _3 | _4 | _5 | _6 | _7 | _8 | _9 | _A | _B | _C | _D | _E | _F | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0xF90_ | 豈 | 更 | 車 | 賈 | 滑 | 串 | 句 | 龜 | 龜 | 契 | 金 | 喇 | 奈 | 懶 | 癩 | 羅 |
0xF91_ | 蘿 | 螺 | 裸 | 邏 | 樂 | 洛 | 烙 | 珞 | 落 | 酪 | 駱 | 亂 | 卵 | 欄 | 爛 | 蘭 |
0xF92_ | 鸞 | 嵐 | 濫 | 藍 | 襤 | 拉 | 臘 | 蠟 | 廊 | 朗 | 浪 | 狼 | 郎 | 來 | 冷 | 勞 |
0xF93_ | 擄 | 櫓 | 爐 | 盧 | 老 | 蘆 | 虜 | 路 | 露 | 魯 | 鷺 | 碌 | 祿 | 綠 | 菉 | 錄 |
0xF94_ | 鹿 | 論 | 壟 | 弄 | 籠 | 聾 | 牢 | 磊 | 賂 | 雷 | 壘 | 屢 | 樓 | 淚 | 漏 | 累 |
0xF95_ | 縷 | 陋 | 勒 | 肋 | 凜 | 凌 | 稜 | 綾 | 菱 | 陵 | 讀 | 拏 | 樂 | 諾 | 丹 | 寧 |
0xF96_ | 怒 | 率 | 異 | 北 | 磻 | 便 | 復 | 不 | 泌 | 數 | 索 | 參 | 塞 | 省 | 葉 | 說 |
0xF97_ | 殺 | 辰 | 沈 | 拾 | 若 | 掠 | 略 | 亮 | 兩 | 凉 | 梁 | 糧 | 良 | 諒 | 量 | 勵 |
0xF98_ | 呂 | 女 | 廬 | 旅 | 濾 | 礪 | 閭 | 驪 | 麗 | 黎 | 力 | 曆 | 歷 | 轢 | 年 | 憐 |
0xF99_ | 戀 | 撚 | 漣 | 煉 | 璉 | 秊 | 練 | 聯 | 輦 | 蓮 | 連 | 鍊 | 列 | 劣 | 咽 | 烈 |
0xF9A_ | 裂 | 說 | 廉 | 念 | 捻 | 殮 | 簾 | 獵 | 令 | 囹 | 寧 | 嶺 | 怜 | 玲 | 瑩 | 羚 |
0xF9B_ | 聆 | 鈴 | 零 | 靈 | 領 | 例 | 禮 | 醴 | 隸 | 惡 | 了 | 僚 | 寮 | 尿 | 料 | 樂 |
0xF9C_ | 燎 | 療 | 蓼 | 遼 | 龍 | 暈 | 阮 | 劉 | 杻 | 柳 | 流 | 溜 | 琉 | 留 | 硫 | 紐 |
0xF9D_ | 類 | 六 | 戮 | 陸 | 倫 | 崙 | 淪 | 輪 | 律 | 慄 | 栗 | 率 | 隆 | 利 | 吏 | 履 |
0xF9E_ | 易 | 李 | 梨 | 泥 | 理 | 痢 | 罹 | 裏 | 裡 | 里 | 離 | 匿 | 溺 | 吝 | 燐 | 璘 |
0xF9F_ | 藺 | 隣 | 鱗 | 麟 | 林 | 淋 | 臨 | 立 | 笠 | 粒 | 狀 | 炙 | 識 | 什 | 茶 | 刺 |
Au moment où j'ai écrit cette partie, nous en étions à Unicode 12.0, version qui contient 137 928 caractères différents. Attention néanmoins, ils ne sont pas juste classés dans l'ordre.
Les caractères UNICODE sont classés en bloc thématique contenant 65536 caractères possibles. Il existe donc beaucoup de valeurs non utilisées puisque les blocs ne sont pas totalement plein loin de là.
Le but est de garantir une durée de vie énorme au système en pouvant rajouter un nombre très important de valeurs.
Justement, Python utilise directement à l'interne ce code pour gérer ces caractères. C'est pour cela que vous pourriez utiliser des noms de variables ou des fonctions en utlisant les caractères de n'importe quelle langue.
Fonctions natives ord et chr
La fonction native chr renvoie le caractère UNICODE correspondant au nombre décimal décimal fourni en argument.
>>> chr(65)
'A'
>>> chr(10000)
'✐'
>>> chr(20000)
'丠'
La fonction native ord fait l'inverse : elle renvoie la valeur UNICODE correspondant au caractère fourni en argument.
>>> ord('A')
65
>>> ord('✐')
10000
>>> ord('丠')
20000
Du coup, si vous cherchez la correspondance entre un caractère et une valeur ASCII ou latin-1, ça marche aussi puisque les valeurs 0-255 d'UNICODE sont compatibles avec ces tables.
12° Créer un programme qui permet d'afficher les caractères UNICODE de l'invervalle [1000;1100].
...CORRECTION...
J'espère que vous avez trouvé tout seul...
Une correction pour la forme.
1
2 | for valeur in range(1000,1101):
print(chr(valeur))
|
Et le résultat attendu :
Ϩ
ϩ
Ϫ
ϫ
Ϭ
ϭ
Ϯ
ϯ
ϰ
ϱ
ϲ
ϳ
ϴ
ϵ
϶
Ϸ
ϸ
Ϲ
Ϻ
ϻ
ϼ
Ͻ
Ͼ
Ͽ
Ѐ
Ё
Ђ
Ѓ
Є
Ѕ
І
Ї
Ј
Љ
Њ
Ћ
Ќ
Ѝ
Ў
Џ
А
Б
В
Г
Д
Е
Ж
З
И
Й
К
Л
М
Н
О
П
Р
С
Т
У
Ф
Х
Ц
Ч
Ш
Щ
Ъ
Ы
Ь
Э
Ю
Я
а
б
в
г
д
е
ж
з
и
й
к
л
м
н
о
п
р
с
т
у
ф
х
ц
ч
ш
щ
ъ
ы
ь
C'est bien gentil tout ça mais ça n'explique pas concrétement comment encoder les caractères.
✎ 13° Fournir un calcul montrant qu'on peut encoder plus de 4 milliards de caractères avec 4 octets.
En nous arrivons au problème majeur de l'UNICODE : comment parvenir à encoder correctement tous ces caractères.
Imaginons qu'on décide d'utiliser 4 octets pour chaque caractère. Cela permet d'aller jusqu'à 4 milliards de caractères, nous avons donc plus de marge qu'avec les tables d'un octet...
Cet encodage brute se nomme UTF-32.
D'où vient ce nom ? De Universal Character Set Transformation Format 32 bits. Ca tombe bien 32 bits, ça donne 4 octets.
Le problème d'UTF-32 vient de la taille des fichiers : il serait 4 fois plus lourd à transporter ou à stocker qu'avec les encodages 1 octet, puisqu'il faudrait 4 octets par caractère.
Un fichier-texte de 100 000 caractères encodé en latin-1 prendrait 100 ko de place mémoire sans compression.
Le même fichier encodé avec UTF-32 occuperait 400 ko.
Et c'est qu'intervient le fameux UTF-8.
6 - UTF-8
L'idée derrière UTF-8 est de pouvoir utiliser les valeurs UNICODE en prenant moins que 4 octets par caractère.
Il est aujourd'hui l'encodage par défaut des systèmes UNIX compatibles (Linux, MacOS) et plus de 95% des pages Web sont encodées en UTF-8.
Nous n'allons pas rentrer dans le détail de la norme ici (ce n'est pas au programme et il s'agit juste d'une technique de codification qui pourrait être aménée à changer ou disparaître).

L'idée est de parvenir à encoder les caractères courants sur un octet, les caractères moins courants sur 2 octets et les autres caractères sur 3 ou 4 octets.
L'idée générale est d'abord que les caractères courants dans la plupart des langages occidentaux (ceux de la table ASCII donc) soient encodés sur 1 octet.
Caractères courants (dans notre culture occidentale)
Pour ces caractères ASCII, on utilise uniquement 7 bits pour le stockage de l'information.
Si le bit de poids fort est à 0
, cela indique que le caractère est encodé sur un seul octet :
Pour ce caractère, on aura toujours en UTF-8 un contenu binaire de la forme : 0xxx xxxx
où x
représente un bit quelconque.
Il y a 7 x
: on peut coder sur 7 bits, donc toutes les valeurs de la table ASCII.
Exemple : le code ASCII du A est 65 en décimal et en binaire 100 0001 .
Son code UTF-8 est donc obtenu en rajoutant 0 devant : 0100 0001 .
Il correspond donc toujours à un octet donnant 65 en décimal. C'est un A.
14° Quelle place mémoire prendrait le texte suivant en étant encodé en ASCII, en UTF-8 puis en UTF-32 ?
>>> texte = "ABCDE"
...CORRECTION...
Il ne s'agit que de caractères ASCII.
Il y a 5 caractères.
En ASCII : 5 octets.
En UTF-8 : 5 octets.
En UTF-32 : 20 octets.
15° Voici un exemple de code permettant de trouver l'encodage UTF-8 d'une chaîne de caractères purement ASCII ici. Remarquez bien que tous les bits commencent à 0.
1
2
3
4
5
6
7 | texte = "ABCDE"
octets = texte.encode('utf-8')
suite_en_decimal = list(octets)
suite_en_binaire = [bin(octet)[2:].rjust(8,'0') for octet in octets]
print(suite_en_decimal)
print(suite_en_binaire)
|
Vous devriez trouver
[65, 66, 67, 68, 69]
['01000001', '01000010', '01000011', '01000100', '01000101']
On obtient bien 4 octets.
16° Relancer en changeant juste l'encodage pour obtenir de l'UTF-32.
1
2
3
4
5
6
7 | texte = "ABCDE"
octets = texte.encode('utf-32')
suite_en_decimal = list(octets)
suite_en_binaire = [bin(octet)[2:].rjust(8,'0') for octet in octets]
print(suite_en_decimal)
print(suite_en_binaire)
|
Vous devriez trouver
[255, 254, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 69, 0, 0, 0]
['11111111', '11111110', '00000000', '00000000', '01000001', '00000000', '00000000', '00000000', '01000010', '00000000', '00000000', '00000000', '01000011', '00000000', '00000000', '00000000', '01000100', '00000000', '00000000', '00000000', '01000101', '00000000', '00000000', '00000000']
Ah zut. Nous obtenons 24 octets et pas 20...
Culture générale, hors NSI
En réalité, les 4 premiers octets sont ce qu'on nomme le BOM : byte order mark. Par convention, le BOM contient 255 et 254. Les placer permet au système de savoir dans quel ordre il doit placer les octets, si on fonctionne en BIG ENDIAN ou LITTLE ENDIAN.
Une chaîne UTF-32 comporte donc toujours 4 octets supplémentaires en début de sa suite d'octets.
Si le système lit 254 - 255 - 0 - 0 : on lui indique qu'il doit lire la suite en BIG ENDIAN.
Si le système lit 255 - 254 - 0 - 0 : on lui indique qu'il doit lire la suite en LITTLE ENDIAN.
Si vous voulez comprendre un peu plus, lisez la suite. Sinon, vous pouvez sortir de la boîte rouge.
...suite...
Ici, nous sommes donc en LITTLE ENDIAN puisqu'on reçoit 255 puis 254. C'est pour cela que les 4 octets bleus sont décodés de cette façon : 65
* 1 + 0
* 28 + 0
* 216 + 0
* 224 = 65.
Si nous avions été en BIG ENDIAN, cela aurait donné : 65
* 224 + 0
* 216 + 0
* 28 + 0
* 1 = 1090519040.
Passons maintenant aux caractères moins courants.
Caractères moins courants (dans notre culture occidentale)
Si le bit de poids fort du premier octet lu est à 1
, cela veut dire qu'il faudra lire plusieurs octets pour trouver la valeur UNICODE du caractère.
Le nombre de bits à 1
avant de rencontrer un premier bit à 0
donne le nombre d'octets à lire pour décoder le caractère.
110x xxxx
veut dire qu'il faut tenir compte de cet octet et du suivant également.
1110 xxxx
veut dire qu'il faut tenir compte de cet octet et des deux suivants.
1111 0xxx
veut dire qu'il faut tenir compte de cet octet et des trois suivants.
Pour les octets suivants justement, l'encodage impose que leurs deux bits de poids forts soient 10
: ils auront donc tous une structure du type 10xx xxxx
.
Code sur 2 octets :
- 110x xxxx - 10xx xxxx
- Cela veut dire qu'il y a 2 octets à lire en tout.
- Il y a 11 x : on peut coder sur 11 bits.
Ces 211 valeurs possibles vont bien entendu être utilisées pour les valeurs assez courantes dans les langages occidentaux. Les lettres accentuées, ect...
Exemple : le "é" est représenté par les deux octets 195
169
. En binaire, cela donne 1100 0011
1010 1001
.
Code sur 3 octets :
- 1110 xxxx - 10xx xxxx - 10xx xxxx
- Cela veut dire qu'il y a 3 octets à lire en tout.
- Il y a 16 x : on peut coder sur 16 bits.
Ici, vont se trouver les caractères vraiment pas courants.
Exemple : le "✐" est représenté par les trois octets 226
156
144
. En binaire, cela donne
1110 0010
1001 1100
1001 0000
.
Code sur 4 octets :
- 11110xxx - 10xx xxxx - 10xx xxxx - 10xx xxxx
- Cela veut dire qu'il y a 4 octets à lire en tout.
- Il y a 21 x : on peut coder sur 21 bits.
Ce sont les caractères encore moins courants que les précédents.
17° Quel est le problème de l'UTF-8 pour les langages qui n'utilisent pas du tout les caractères usuels ASCII ?
...CORRECTION...
Pour ces langages, UTF-8 n'est pas spécialement performant puisque les caractères encodés sur 1 octet ne seront pas utilisés. De plus, la majorité de leurs caractères risquent de se retrouver dans la catégorie 3 OCTETS.
Ainsi, un texte asiatique a toute les chances de peser 3 fois plus lourd qu'un texte anglais.
UTF-16
L'encodage UTF-16 est utilisé notamment dans les pays asiatiques. Tous les caractères sont encodés sur 2 octets ou 4 octets. Mais leurs caractères spécifiques sont présents dans la zone des 2 OCTETS. Cette encodage est donc plus performant que l'UTF-8 sur ce genre de langage.
Il nous reste à avoir une explication sur l'image d'introduction.

Et ça marche aussi avec Perceval :

Ce genre d'erreur arrivait assez couramment sur le Web à l'époque de la montée en puissance de l'UTF-8 alors que latin-1 était encore très présent.
Un Webmaster publiait ces pages HTML en UTF-8 (sans préciser son encodage dans sa page, dans la balise HEAD) et le navigateur du client avait lui latin-1 comme encodage par défaut s'il n'avait aucune indication de l'encodage à utiliser.
✎ 18° Utiliser le programme ci-dessous pour visualiser la mauvaise "traduction". Expliquer ensuite le plus clairement possible pourquoi le "é" se transforme en deux caractères "é".
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | encodage_depart = 'utf-8'
encodage_recepteur = 'latin-1'
texte_origine = "Martine écrit en " + encodage_depart
print("1) On a un texte d'origine")
print(texte_origine)
octets = texte_origine.encode(encodage_depart)
print(f'\n2) On encode le texte en {encodage_depart} et on envoie des octets')
print(octets)
texte_decode = octets.decode(encodage_recepteur)
print('\n3) On recoit les octets mais on décode avec un autre encodage')
print(texte_decode)
|
Ca marche aussi avec Perceval bien entendu :
1) On a un texte d'origine
C'est écrit en utf-8?
2) On encode le texte en utf-8 et on envoie des octets
b"C'est \xc3\xa9crit en utf-8?"
3) On recoit les octets mais on décode avec un autre encodage
C'est écrit en utf-8?
19° Réaliser maintenant l'encodage en latin-1. Tenter de lire les octets en utf-8. Quel est le problème ?
...CORRECTION...
Cette fois, cela provoque une erreur car toutes les valeurs d'octets ne sont pas autorisées en UTF-8. Souvenez-vous de l'histoire des 1 au début du premier octet et des suivants qui doivent commencer par 10... Si les octets reçus ne suivent pas cette logique, le programme ne va pas réussir à décoder, même mal le texte.
Or ici, le "é" encodé en latin-1 est un octet qui commence bien par un 1 puisqu'il est supérieur à 127. Mais l'octet suivant ne commence pas par 10. Et ça ne va pas...
Les QCM pour savoir ce qu'il faut retenir pour la fin.
✎ 20° Répondre aux questions suivantes :
Quel a été le premier encodage standardisé des caractères ?
- A : ASCII
- B : cp-437
- C : latin-1 ou iso8859_1
- D : UTF-8
Combien d'associations valeurs-caractères peuvent encoder au maximum les tables du type latin-1 ?
- A : 127
- B : 128
- C : 255
- D : 256
UNICODE est
- A : un encodage qui remplace maintenant latin-1
- B : une simple association d'un entier et d'un caractère
- C : un encodage sur 1 octet
- D : un encodage sur 4 octets
UTF-8 est
- A : une autre façon d'encoder les tables 1 octet (donc 8 bits)
- B : un encodage basé sur UNICODE dans lequel les caractères prennent de 8 octets
- C : la 8e version de l'encodage UTF, incluant le symbole monétaire EURO
- D : un encodage basé sur UNICODE dans lequel les caractères prennent de 1 à 4 octets
Activité publiée le 09 02 2020
Dernière modification : 13 12 2020
Auteur : ows. h.