« UNICODE » : différence entre les versions

De knowledge
Aller à la navigation Aller à la recherche
mAucun résumé des modifications
 
(6 versions intermédiaires par le même utilisateur non affichées)
Ligne 1 : Ligne 1 :
== Généralités ==
== Généralités ==
[[Fichier:1280px-Writing Systems.png|vignette]]
[[Fichier:1280px-Writing Systems.png|vignette]]
Il n'y a pas que l'anglais dans le monde!
'''<big>Il n'y a pas que l'anglais dans le monde!</big>'''


Si si, même si notre français s'accommode sans trop de soucis à [[ASCII|l'ASCII]] d'autres langues sont définitivement pas latines et ne savent pas. Le russe, l'arabe le chinois... (exemple ci-contre)
Si si, même si notre français s'accommode sans trop de soucis à [[ASCII|l'ASCII]] d'autres langues sont définitivement pas latines et ne savent pas. Le russe, l'arabe le chinois... (exemple ci-contre)
Ligne 37 : Ligne 37 :
Là on est plus subtil mais c'est plus compliqué a traiter. Chaque caractère peut être codé sur un nombre variables d'octets (UTF-8) ou de mots (UTF-16)
Là on est plus subtil mais c'est plus compliqué a traiter. Chaque caractère peut être codé sur un nombre variables d'octets (UTF-8) ou de mots (UTF-16)


UTF-8 est massivement utilisé dans tous les domaines (web, machines Linux etc) mais je crois que Windows s'acharne à utiliser UTF-16 (les processeur 16 bits des débuts y sont peut être pour quelque chose).  
UTF-8 est massivement utilisé dans tous les domaines (web, machines Linux etc.) mais Windows s'acharne à utiliser UTF-16 (les processeur 16 bits des débuts y sont peut être pour quelque chose).  


==== UTF-8 ====
==== UTF-8 ====
C'est le plus utilisé et le plus complexe à lire.
C'est le plus utilisé et le plus complexe à lire.


On lit les octets un par un. Pour chaque octet on regarde son bit de poids fort.
* Si c'est un 0 alors les 7 bits suivants sont le caractère ASCII qui correspond. '''ON EST DONC COMPATIBLE ASCII''' !
* Si le bit de poids fort est à 1 ca se complique... On compte alors les bits à 1 avant de tomber sur un 0. Ce nombre de bits à 1 corresponds à la longueur du caractère!
** 110 (premier bit pour dire que c'est à taille variable et le second pour dire qu'il y en a encore un à lire) il nous reste alors 5 bits de "payload" sur ce caractère. Comme on a vu qu'il y avait un qui suivait, on le lit.
** 1110 on devra lire deux octets ensuite et il reste 4 bits de payload.
** 11110 on devra lire trois octets ensuite et il ne reste plus que deux bits de payload car le premier doit être à zéro je ne sais pas pourquoi.
** 10 a un rôle spécial. C'est un octet de complément. Si on a un premier que commence par 110xxxxx il sera suivi d'un octet de valeur 19xxxxxx. Donc on peut coder sur deux octets des caractères de 11 bits (les 2048 premiers caractères UNICODE)
Cette subtilité des octets commençant par 10 permet à un process de lecture série (UART par exemple) de savoir "par où commencer". Lorsque on commence à lire on ignore tous les octets en 10xxxxxx car c'est la fin d'un caractère dont on a loupé le début. On commence à décoder dès qu'on a un octet ne commençant pas par 10.
Le résumé est donné dans ce tableau issue de [https://fr.wikipedia.org/wiki/UTF-8 Wikipédia].
{| class="wikitable"
{| class="wikitable"
!Caractères codés
!Caractères codés
Ligne 67 : Ligne 79 :
|F0 à F3
|F0 à F3
| rowspan="2" |4 octets, codant jusqu’à 21 bits
| rowspan="2" |4 octets, codant jusqu’à 21 bits
|}
On note l'utilisation de <kbd><var>ƀ</var></kbd> caractère 180 en UNICODE, <code>'''C6 80'''</code> en UTF-8  (Latin Small Letter B With Stroke)
On note qu'on perds plein de places dans le cas des caractères multi-bits.
Dans le cas de deux octets:
<kbd>110<var>ƀ·ƀƀƀƀ</var> 10<var>ƀƀ·ƀƀƀƀ</var></kbd> 
On pourrait imagine de coder un caractère de 7 bits:
<kbd>110<var>ƀ·ƀƀƀƀ</var> 10<var>ƀƀ·ƀƀƀƀ</var></kbd> 
Un <code>'A'</code> (<code>0x41</code>) <code>.000 0100</code> en binaire 7 bits donnerait:
<code>1100·0000 1000·0100</code> soit <code>0xC0 0x84.</code>Cela ferait que le 'A' pourrait avoir de multiple codage <code>0x41</code>, <code>0xC0 0x84</code>ou encode des codages sur 3 ou 4 octets mais c'est INTERDIT. Le seul codage de <code>'A'</code> est <code>0x41</code>.
Ceci explique la troisième colonne du tableau ci-dessus. Toutes les valeurs ne sont pas possibes.
==== UTF-16 ====
Je trouve que c'est le plus moche. C'est un mix entre un codage en binaire brut de du codage en taille variable. C'est compliqué a décoder et incompatible avec ASCII. En plus ce sont des données sur 16 bits donc on a la version  Big-endian UTF-16 et Little-endian UTF-16.
A priori Windows est dans la secte "gros indien".
===== UCS-2 =====
{| class="wikitable"
|+
|[[Fichier:Attention.png|sans_cadre|55x55px]]
|La norme UCS-2 , ancienne version d'Unicode, est limitée à 65 535 caractères.
Cependant, l'industrie du traitement de données a besoin de plus de 94 000 caractères ; la norme UCS-2 a été remplacée par la norme Unicode UTF-16 .
|}
Certains outils parlent encode de UCS-2.
Avec ma version de notepad++ (un peu vielle je l'accorde)
[[Fichier:Version-notepad++.png|sans_cadre|300x300px]]
Je peux choisir l'encodage :
[[Fichier:Notepad-encoding.png|sans_cadre]]
Si je teste les 5 modes (+ le même fichier tapé avec vi sans les accents) ci-dessus:
La commande POSIX <code>file</code> donne :<syntaxhighlight lang="text">
file defaut*
defaut.txt:          ASCII text, with CRLF line terminators
defaut-ANSI.txt:    ISO-8859 text, with CRLF line terminators
defaut-UCSBE.txt:    Big-endian UTF-16 Unicode text, with CRLF line terminators
defaut-UCSLE.txt:    Little-endian UTF-16 Unicode text, with CRLF line terminators
defaut-UTF8.txt:    UTF-8 Unicode text, with CRLF line terminators
defaut-UTF8+BOM.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
</syntaxhighlight>Dans ce cas UCS-2 peut être lut pas UTF-16 mais pas l'inverse. (cf remarque en début de chapitre.)
Ensuite je n'ai pas testé l'ouverture de "vrai" UTF-16 avec des caractères pas gérés en UCS-2 avec notepad++
== Méthodes historiques ==
Avant UNICODE (1991) et même UCS-2 il fallait écrire des textes avec d'autres caractères que l'anglais standard.
Les fabricants avaient bien fait des tables d'ASCII étendu (on utilise les 128 caractères après 127) mais rien n'était compatible avec rien! Le codage d'un simple "é" donnait des migraine aux développeurs, DBA, admin réseau (L7) etc.
La norme [https://fr.wikipedia.org/wiki/ISO/CEI_8859 ISO/IEC 8859] était là pour ça.
Elle définissait tout une série de "code page" pour chacun des pays ou zone linguistique.
Chaque langue plutôt type d'écriture a eu sa propre "sous norme" ISO 8859-'''''n''''' avec '''''n''''' un entier décrivant la type d'écriture.
'''''<big>n</big>''''' peut valoir (entre autre):
{| class="wikitable"
!''n''
!Nom
!Langues couvertes
|-
|1
|''latin-1'' ou ''européen occidental''
|L'allemand, l'anglais, le basque, le catalan, le danois, l'écossais, l'espagnol, le féroïen, le finnois (partiellement), le français (partiellement, il manque notamment l’e dans l'o œ et le Ÿ), l'islandais, l'irlandais, l'italien, le néerlandais (partiellement), le norvégien, le portugais, le rhéto-roman et le suédois.
|-
|2
|''latin-2'' ou ''européen central''
|Le bosniaque, le croate, le polonais, le tchèque, le slovaque, le slovène et le hongrois.
|-
|3
|''latin-3'' ou ''européen du Sud''
|Le turc, le maltais, et l'espéranto
|-
|4
|''latin-4'' ou ''européen du Nord''
|L'estonien, le letton, le lituanien, le groenlandais, et le sami.
|-
|5
|''cyrillique''
|La plupart des langues slaves utilisant un alphabet cyrillique, y compris le biélorusse, le bulgare, le macédonien, le russe, le serbe et l'ukrainien (partiellement).
|-
|6
|''arabe''
|Arabe. Nécessite la capacité d'affichage bi-directionel (comme '''''n'''''=8 hébreu)
|-
|...
|
|Plein d'autres (14 pour les langues celtiques comme le manois et le breton)
|-
|15
|''latin-9'' ou parfois de façon impropre ''latin-0''
|Apparu en 1998!
Révision de ''8859-1'' qui abandonne quelques symboles peu utilisés, les remplaçant avec le symbole de l'euro € (remplaçant le signe de monnaie ¤) et les lettres Š, š, Ž, ž, Œ, œ, et Ÿ, ce qui complète la couverture du français, du finnois et de l'estonien.
'''APPARITION DE l'EURO €'''
|-
|16
|''latin-10'' ou ''européen du Sud-Est''
|Prévu pour l’albanais, le croate, le hongrois, l'italien, le polonais, le roumain et le slovène, mais aussi le finnois, le français, l'allemand et l’irlandais (en nouvelle orthographe).
|}
Exemple de caractères codés pour les différentes versions '''''<big>n</big>''''' du code ISO 8859 (en français on utilisait 1 puis 15)
{| class="wikitable"
! colspan="14" |Numéro de partie d’ISO 8859 (''<big>n</big>'')
|-
!Déc
!Hex
!1
!2
!3
!4
!5
!6
!7
!8
!9
!10
!11
!13
!14
!15
!16
|-
!160
!A0
| colspan="15" |''NBSP''
|-
!161
!A1
|
|‘
|
|ก
|”
|Ḃ
|-
!162
!A2
|
|’
|ข
|ḃ
|-
!163
!A3
|
|ฃ
|-
!164
!A4
|€
|ค
|€
|€
|-
!165
!A5
|
|
|₯
|ฅ
|„
|„
|-
!166
!A6
|
|ฆ
|Ḋ
|-
!167
!A7
|
|ง
|-
!168
!A8
|
|จ
|Ẁ
|}
{| class="wikitable"
|+
|[[Fichier:Attention.png|sans_cadre|55x55px]]
|On note le code 164 qui valait <big><code>¤</code></big> (symbole générique de la devise) et qui vaut <big><code>€</code></big> depuis ISO 8859-15 (mais aussi le cyrillique n=5 le grec n=7 cet  car ces codes ont été crées en 1999 où l'EURO était déjà prévu tandis que la Grèce était dans l'UE et ainsi que certains pays d'Europe centrale et orientale)
|}
|}

Dernière version du 21 janvier 2026 à 14:57

Généralités

Il n'y a pas que l'anglais dans le monde!

Si si, même si notre français s'accommode sans trop de soucis à l'ASCII d'autres langues sont définitivement pas latines et ne savent pas. Le russe, l'arabe le chinois... (exemple ci-contre)

Cela nous fait pas mal de caractères à coder : Ա ࠂ ô ᚡ ... et y'en a d'autres!

On s'est mis d'accord pour créer le code UNICODE. https://www.compart.com/fr/unicode/

Chaque caractère à un numéro et on considère des blocs.

  • Pour les 127 premiers c'est le même numéro que l'ASCII. Tout va bien nos programmes en C resteront codés de la même façon!
  • Entre 128 et 255 on a des caractères dit ASCII étendu ou Latin 1. Ce sont les extensions à l'ASCII qui permettent d'écrire l'ensemble des langues européennes latines.

On a ensuite beaucoup de blocs pour des multitudes de systèmes d'écritures mais aussi pour des usages spécifiques, scientifique, linguistiques...

  • L'un des derniers est le bloc des idéogrammes CJK unifiés (à partir de caractère 196 608 et pour les 4 939 suivants (ca va de 𰀀 196608 à 𱍊 201546)

C'est ce qui a été normalisé par l'ISO et l'Europe dans la norme ISO/CEI 10646.

Codage

Ces caractères sont donc codés de zéro (le null ASCII) à 0x10 FFFF ou 1 114 111(un million cent quatorze mille cent douze caractères). En gros, et pour le moment, ca rentrerait sur 24 bits. On pourrait se dire qu'à partir de dorénavant on coderait tous les textes en 24 (32 c'est un multiple de 8) bits. Cependant, pour ceux qui ont la chance de pouvoir utiliser de l'ASCII ca fait clairement du ×4 en volume ce qui est dommage.

On a fait plusieurs systèmes que les différents utilisateurs peuvent choisir tant qu'ils se mettent d'accord au départ.

7 bits ASCII jusque là tout va bien on maitrise

Pour le reste ça se complique:

UTF32

C'est le plus simple mais celui qui prends le plus de place. Si on se mets d'accord sur ce codage au départ, tous les caractères seront une suite de 4 octets. Le chiffre zéro par exemple sera codé : 00 00 00 30 et le π (pi minuscule) sera noté 00 00 03 C0.

C'est brutal mais c'est très simple. On peut tout coder avec ça sans se poser de questions (sauf qu'il faut acheter de la RAM, du disque et de la bande passante en ×4)

Les encodages a taille variables.

Là on est plus subtil mais c'est plus compliqué a traiter. Chaque caractère peut être codé sur un nombre variables d'octets (UTF-8) ou de mots (UTF-16)

UTF-8 est massivement utilisé dans tous les domaines (web, machines Linux etc.) mais Windows s'acharne à utiliser UTF-16 (les processeur 16 bits des débuts y sont peut être pour quelque chose).

UTF-8

C'est le plus utilisé et le plus complexe à lire.

On lit les octets un par un. Pour chaque octet on regarde son bit de poids fort.

  • Si c'est un 0 alors les 7 bits suivants sont le caractère ASCII qui correspond. ON EST DONC COMPATIBLE ASCII !
  • Si le bit de poids fort est à 1 ca se complique... On compte alors les bits à 1 avant de tomber sur un 0. Ce nombre de bits à 1 corresponds à la longueur du caractère!
    • 110 (premier bit pour dire que c'est à taille variable et le second pour dire qu'il y en a encore un à lire) il nous reste alors 5 bits de "payload" sur ce caractère. Comme on a vu qu'il y avait un qui suivait, on le lit.
    • 1110 on devra lire deux octets ensuite et il reste 4 bits de payload.
    • 11110 on devra lire trois octets ensuite et il ne reste plus que deux bits de payload car le premier doit être à zéro je ne sais pas pourquoi.
    • 10 a un rôle spécial. C'est un octet de complément. Si on a un premier que commence par 110xxxxx il sera suivi d'un octet de valeur 19xxxxxx. Donc on peut coder sur deux octets des caractères de 11 bits (les 2048 premiers caractères UNICODE)

Cette subtilité des octets commençant par 10 permet à un process de lecture série (UART par exemple) de savoir "par où commencer". Lorsque on commence à lire on ignore tous les octets en 10xxxxxx car c'est la fin d'un caractère dont on a loupé le début. On commence à décoder dès qu'on a un octet ne commençant pas par 10.

Le résumé est donné dans ce tableau issue de Wikipédia.

Caractères codés Représentation binaire UTF-8 Premier octet valide (hexadécimal) Signification
U+0000 à U+007F 0ƀƀƀ·ƀƀƀƀ 00 à 7F 1 octet, codant jusqu’à 7 bits
U+0080 à U+07FF 110ƀ·ƀƀƀƀ 10ƀƀ·ƀƀƀƀ C2 à DF 2 octets, codant jusqu’à 11 bits
U+0800 à U+FFFF 1110·ƀƀƀƀ 10ƀƀ·ƀƀƀƀ 10ƀƀ·ƀƀƀƀ E0 à EF 3 octets, codant jusqu’à 16 bits
U+10000 à U+10FFFF 1111·00ƀƀ 10ƀƀ·ƀƀƀƀ 10ƀƀ·ƀƀƀƀ 10ƀƀ·ƀƀƀƀ F0 à F3 4 octets, codant jusqu’à 21 bits

On note l'utilisation de ƀ caractère 180 en UNICODE, C6 80 en UTF-8 (Latin Small Letter B With Stroke)

On note qu'on perds plein de places dans le cas des caractères multi-bits.

Dans le cas de deux octets:

110ƀ·ƀƀƀƀ 10ƀƀ·ƀƀƀƀ

On pourrait imagine de coder un caractère de 7 bits:

110ƀ·ƀƀƀƀ 10ƀƀ·ƀƀƀƀ

Un 'A' (0x41) .000 0100 en binaire 7 bits donnerait:

1100·0000 1000·0100 soit 0xC0 0x84.Cela ferait que le 'A' pourrait avoir de multiple codage 0x41, 0xC0 0x84ou encode des codages sur 3 ou 4 octets mais c'est INTERDIT. Le seul codage de 'A' est 0x41.

Ceci explique la troisième colonne du tableau ci-dessus. Toutes les valeurs ne sont pas possibes.

UTF-16

Je trouve que c'est le plus moche. C'est un mix entre un codage en binaire brut de du codage en taille variable. C'est compliqué a décoder et incompatible avec ASCII. En plus ce sont des données sur 16 bits donc on a la version Big-endian UTF-16 et Little-endian UTF-16.

A priori Windows est dans la secte "gros indien".

UCS-2
La norme UCS-2 , ancienne version d'Unicode, est limitée à 65 535 caractères.

Cependant, l'industrie du traitement de données a besoin de plus de 94 000 caractères ; la norme UCS-2 a été remplacée par la norme Unicode UTF-16 .

Certains outils parlent encode de UCS-2.

Avec ma version de notepad++ (un peu vielle je l'accorde)

Je peux choisir l'encodage :

Si je teste les 5 modes (+ le même fichier tapé avec vi sans les accents) ci-dessus:

La commande POSIX file donne :

file defaut*
defaut.txt:          ASCII text, with CRLF line terminators
defaut-ANSI.txt:     ISO-8859 text, with CRLF line terminators
defaut-UCSBE.txt:    Big-endian UTF-16 Unicode text, with CRLF line terminators
defaut-UCSLE.txt:    Little-endian UTF-16 Unicode text, with CRLF line terminators
defaut-UTF8.txt:     UTF-8 Unicode text, with CRLF line terminators
defaut-UTF8+BOM.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators

Dans ce cas UCS-2 peut être lut pas UTF-16 mais pas l'inverse. (cf remarque en début de chapitre.)

Ensuite je n'ai pas testé l'ouverture de "vrai" UTF-16 avec des caractères pas gérés en UCS-2 avec notepad++

Méthodes historiques

Avant UNICODE (1991) et même UCS-2 il fallait écrire des textes avec d'autres caractères que l'anglais standard.

Les fabricants avaient bien fait des tables d'ASCII étendu (on utilise les 128 caractères après 127) mais rien n'était compatible avec rien! Le codage d'un simple "é" donnait des migraine aux développeurs, DBA, admin réseau (L7) etc.

La norme ISO/IEC 8859 était là pour ça.

Elle définissait tout une série de "code page" pour chacun des pays ou zone linguistique.

Chaque langue plutôt type d'écriture a eu sa propre "sous norme" ISO 8859-n avec n un entier décrivant la type d'écriture.

n peut valoir (entre autre):

n Nom Langues couvertes
1 latin-1 ou européen occidental L'allemand, l'anglais, le basque, le catalan, le danois, l'écossais, l'espagnol, le féroïen, le finnois (partiellement), le français (partiellement, il manque notamment l’e dans l'o œ et le Ÿ), l'islandais, l'irlandais, l'italien, le néerlandais (partiellement), le norvégien, le portugais, le rhéto-roman et le suédois.
2 latin-2 ou européen central Le bosniaque, le croate, le polonais, le tchèque, le slovaque, le slovène et le hongrois.
3 latin-3 ou européen du Sud Le turc, le maltais, et l'espéranto
4 latin-4 ou européen du Nord L'estonien, le letton, le lituanien, le groenlandais, et le sami.
5 cyrillique La plupart des langues slaves utilisant un alphabet cyrillique, y compris le biélorusse, le bulgare, le macédonien, le russe, le serbe et l'ukrainien (partiellement).
6 arabe Arabe. Nécessite la capacité d'affichage bi-directionel (comme n=8 hébreu)
... Plein d'autres (14 pour les langues celtiques comme le manois et le breton)
15 latin-9 ou parfois de façon impropre latin-0 Apparu en 1998!

Révision de 8859-1 qui abandonne quelques symboles peu utilisés, les remplaçant avec le symbole de l'euro € (remplaçant le signe de monnaie ¤) et les lettres Š, š, Ž, ž, Œ, œ, et Ÿ, ce qui complète la couverture du français, du finnois et de l'estonien. APPARITION DE l'EURO €

16 latin-10 ou européen du Sud-Est Prévu pour l’albanais, le croate, le hongrois, l'italien, le polonais, le roumain et le slovène, mais aussi le finnois, le français, l'allemand et l’irlandais (en nouvelle orthographe).

Exemple de caractères codés pour les différentes versions n du code ISO 8859 (en français on utilisait 1 puis 15)

Numéro de partie d’ISO 8859 (n)
Déc Hex 1 2 3 4 5 6 7 8 9 10 11 13 14 15 16
160 A0 NBSP
161 A1 ¡ Ą Ħ Ą Ё ¡ Ą ¡ Ą
162 A2 ¢ ˘ ˘ ĸ Ђ ¢ ¢ Ē ¢ ¢ ą
163 A3 £ Ł £ Ŗ Ѓ £ £ £ Ģ £ £ £ Ł
164 A4 ¤ ¤ ¤ ¤ Є ¤ ¤ ¤ Ī ¤ Ċ
165 A5 ¥ Ľ Ĩ Ѕ ¥ ¥ Ĩ ċ ¥
166 A6 ¦ Ś Ĥ Ļ І ¦ ¦ ¦ Ķ ¦ Š Š
167 A7 § § § § Ї § § § § § § § §
168 A8 ¨ ¨ ¨ ¨ Ј ¨ ¨ ¨ Ļ Ø š š
On note le code 164 qui valait ¤ (symbole générique de la devise) et qui vaut depuis ISO 8859-15 (mais aussi le cyrillique n=5 le grec n=7 cet car ces codes ont été crées en 1999 où l'EURO était déjà prévu tandis que la Grèce était dans l'UE et ainsi que certains pays d'Europe centrale et orientale)