Unicode

Codage des caractères

Voir ici un survol historique du codage des caractères

Que retenir ?

  1. En Python 3 le type string (chaîne de caractères) est codé en Unicode,à chaque caractère est associé un code, un entier en hexadécimal, par exemple la lettre a a pour code U+61 (en hexadécimal 61), le chiffre 1 a pour code U+31

    Ce que l'on nomme Basic Latin est codé de 0x00 à 0x7F (128) et correspond ce qui anciennement s'appelait le code ASCII

    D'autres codages: comme é -> 0xE9, œ -> 0x0153 (deux octets),β -> 0x03b1 (deux octets),π -> 0x03C0 , l' équivalent du d en russe la lettre д a pour code en hexadécimal 0x0434

    Voici un exemple sur 3 octets 𝔐 -> 0x1D510

    Beaucoup d'autres exemples ici

  2. En machine il n' y a que des octets, et la transformation du code Unicode en octets, s'appelle l'encodage

    L'encodage le plus utilisé de par le monde est à l'heure actuelle l'UTF-8 (pour Unicode Transformation Format) et 8 pour octets

    Concrètement si le code du caractère est < 128, l' encodage se fait sur un octet celui du code

    Sinon l'encodage donnera une séquence de deux, trois ou quatre octets éventuellement par la transformation suivante:

Unicode et fonction built-in Python

Il s'agit de vérifier à partir de fonctions Python le "hack" de l'utf-8

  1. Regardons le cas de la lettre Δ dont le code Unicode est U+0394
  2. En tapant dans l'interpréteur Python s = chr(0x394) le caractère Δ est affecté à s
  3. Si on veut les octets (bytes) on utilise la commande s.encode() et on obtient deux octets sous la forme b'\xce\x94'
  4. Vérifions que que 0x0394 -> 0xce94 correspond bien à l'encodage utf-8 pour un code de 2 octets:

    Convertissons le code Unicode hexadécimal 0x0394 sous la forme de deux octets, on obtient 00000011 10010100 (on fait bin(int(0x0394,16)))

  5. On forme le premier octet en ajoutant après la séquence 110 les trois derniers bits de 00000011 et les deux premiers de 10010100, donc on obtient

    11001110 qui en hexadécimal est 0xce

    Le deuxième octet commence par 10 avec à la suite les bits restants du deuxième octet du code c'est à dire:

    10010100 qui en hexadécimal est 0x94

  6. Comment fait on alors pour ne pas se tromper dans l'opération inverse de décodage ?

    Pourquoi ne peut on pas se tromper s'il faut décoder 11001110 10010100 01111000 ? Pourquoi on ne peut obtenir que Δx ?

    Lorsqu'on lit un octet les premiers bits sont significatifs, on enlève de l'octet les éventuels 1 et le premier zéro, le nombre de 1 obtenus renseigne sur les octets qu'il faudra traiter ensemble, ainsi dans notre exemple 110 signifie qu'il faut traiter les deux octets 11001110 et 10010100 ensemble

    Un octet seul commence toujours par 0, si un octet commence par 10, c'est qu'il fait partie d'un groupe de 2, 3 ou 4 octets

    Il faut regarder un des octets qui le précédent pour avoir le nombre d'octets du groupe :

    110 -> 2 octets, 1110 -> 3 octets, 11110 -> 4 octets

Exercice

  1. Construire une fonction stringToBytes(s) qui traduit une chaine de caractères dont le code Unicode est <= 128 en une chaine d'octets, par exemple pour s='Hello' on doit obtenir b'\x72\x101\x108\x108\x111' (utiliser la fonction ord() par exemple ord('H') retourne 72 et la fonction join())
  2. Construire une fonction bytesToString(s) qui traduit une chaine d'octets en une chaine de caractères ( on suppose que tous les caractères ont été encodés sur 8 bits). Tester sur s = '00110000 01110100 01100101 01110100 00110001

Chiffrement de César

A partir d'un texte en anglais (lettres minuscules sans accent) il s'agit de remplacer chaque lettre du texte, par un caractère "image" décalé toujours d'un même nombre (la clef) dans l'alphabet latin

Par exemple si la clef est 3 la lettre a sera remplacée par d et le texte "programming is fun !" devient "surjudpplqj lv ixq !"

Exercice

  1. Construire une fonction chiffrerCesar(chaine,clef) qui transforme une chaine de caractères chaine par la methode de César à partir de l'entier clef < 26
  2. Faire évoluer cette fonction de telle sorte qu'en paramètre il y a le nom d'un fichier texte que l'on lira en lecture et on écrira en écriture dans un autre fichier texte (utiliser ce fichier )
  3. Construire une fonction dechiffrerCesar(chaine) qui transforme une chaine de caractères chaine en 25 autres chaines possibles