chaînechaînechaînechaînechaînechaînechaînechaînechaînechaînechaînechaîne NSI Ascii, UTF8

Représentation d’un texte en machine.Exemples des encodages ASCII, ISO-8859-1,Unicode

Représentation des données: types et valeurs de base

Plan

Introduction

Lors de l’apparition des premiers calculateurs électroniques (l’ENIAC par exemple en 1945), l’homme ne pouvait interagir avec ce dernier que par le biais de cartes perforées. Ces cartes ont été inventées en 1725 par Basile Bouchon pour les orgues de barbarie. Ces cartes ont ensuite été employées pour les métiers à tisser et Jacquard améliore ce système en 1801 et devient un leader du métier à tisser. En 1908 le mathématicien Charles Babbages a l’idée d’utiliser ces cartes perforées pour la réalisation de calculateurs.

Il est bien évident que communiquer ainsi n’est pas très pratique. Au début des années 60, les premiers ordinateurs personnels font leur apparition (ils n’ont pas encore d’écran mais un clavier et un rouleau pour imprimer les réponses). Il fut donc alors nécessaire de trouver comment manipuler numériquement les nombres et alphabets. Un ensemble de glyphes (le dessin des caractères) est stocké dans une police de caractères. Afin de pouvoir appeler n’importe quel glyphe, on associe des valeurs numériques aux glyphes. Ainsi la lettre « A » pourra s’afficher de différentes manières mais n’aura qu’une seule valeur associée : 65 en décimal.

ASCII

Lors de la création des premiers ordinateurs, le traitement des bits n’était pas très fiable, il arrivait des erreurs lors du traitement des signaux et un 11011011 pouvait très bien se transformer en 100111011…on n’aurait donc plus le même caractère affiché ! Pour contourner ce problème, le bit de poids fort (le plus à gauche) servira de bit de parité : il vaut 1 ou 0 afin que le nombre de 1 dans l’octet soit pair. Ainsi, si l’on a le caractère 10 001 101 au départ et qu’après traitement on récupère 10 101 101 on sait qu’il y a une erreur puisque l’on a un nombre impair de 1.

Il reste donc 7 bits pour coder les différents caractères soit 128 possibilités. C’est la table ASCII. (prononcer « as qui »), 1963. “American Standard Code for Information Interchage”.

128 code c’est assez peu et on en utilise 95 pour les caractères imprimables. Pour l’anglais, langue sans accent, cela suffit mais pour pouvoir afficher d’autres langues c’est insuffisant.

Plutôt que de vous donner la table ASCII, vous allez la faire afficher par Python.

Python permet d’afficher un caractère à partir de son code avec la commande chr(valeur du caractère). Il permet aussi de donner le code d’un caractère avec la commande ord("a") par exemple. Le programme suivant permet donc d’afficher la table ASCII

for i in range(128) :
	   print(i,chr(i))
	

Notez que nos lettres accentuées ne figurent pas dans cette table ascii.

ISO 8859

Les ordinateurs devenant plus fiables, le bit de parité n’avait plus d’utilité. On décide alors de l’utiliser ce qui permet de disposer de 256 codes. C’est la norme ISO 8859 (Organisation internationale de normalisation). Afin de s’adapter aux différents langages, il existe différentes normes ISO 8859. L’'ISO 8859-1 (latin-1), a longtemps été "l'encodage par défaut". Il couvre la majorité des langues de l'Europe Occidentale. L’'ISO 8859-15 (latin-9), est une version plus récente de l'ISO 8859-1, comprenant aussi le symbole euro, et quelques caractères spéciaux. La norme ISO conserve les 128 premiers caractères de la table ASCII.

A l’arrivée d’internet, années 90, les échanges internationaux mettent en évidence les défauts de la norme ISO 8859. Chaque langue peut certes être utilisée mais lorsque l’on passe d’un pays à l’autre, la traduction d’un ISO 8859 à un autre ne peut pas être cohérent. En français il manque toujours le “œ”, le “ÿ” et leurs majuscules !

Un document écrit dans un encodage et ouvert ensuite par un logiciel qui l’interprète dans un autre encodage, n’affichera pas tous les caractères correctement hors de la plage ASCII. Essayez avec notepad++, enregistrez sous un format puis ouvrez le avec un autre.

Unicode UTF-8

La solution : l’Unicode. L'unicode est une norme crée en 1990. Cette norme attribue un numéro à chaque caractère sans tenir compte de la manière dont va le coder. Nous avons vu que la table Ascii va jusqu'au caractère 127 et la table Iso 8859 jusqu'au 255. La table unicode des 255 premiers caractères à les mêmes valeurs que celle de l'iso 8859. Mais la table unicode contient bien d'autres caractères, au delà de 255. Par exemple le signe €, a pour point de code héxadécimal (son unicode): U+20AC. Cela fait bien plus que 255 et on verra que le codage UTF-8 de € n'est pas 20ACh.

Un des nouveaux format d'encodage de l'unicode et le plus utilisé est l'UTF-8 pour 8-Bit Universal Character Set Transformation Format », en français : « format de transformation du jeu universel de caractères 8 bits ». L’UTF-8 code les caractères en utilisant jusque 4 octets. Il attribue à chaque caractère Unicode existant une séquence de bits précise que l’on peut également lire comme un nombre binaire et offre 221 combinaisons. La force de cette norme est de ne pas forcément utiliser 4 octets. La table Ascii est d’ailleurs codée sur 8 bits d’où son nom UTF-8! Quelle est l’astuce ? Pour savoir combien d’octets on va utiliser les bits de poids fort du premier octet (celui de gauche) et pour savoir qu’un octet est la suite du précédent on commence par 10 :

Codes

Encodage en UTF-8

Caractères disponibles dans cet intervalle

jusqu’à U+007F (27-1)

0bbbbbbb

latin de base (ASCII)

jusqu’à U+07FF (211-1)

110bbbbb 10bbbbbb

alphabets d’Europe et du Moyen-Orient 3

jusqu’à U+FFFF (216-1)

1110bbbb 10bbbbbb 10bbbbbb

la quasi-totalité des alphabets actuels ( BMP )

jusqu’à U+10FFFF (221-1)

11110bbb 10bbbbbb 10bbbbbb 10bbbbbb

tous les caractères

Python nous dit que le caractère € a pour code scalaire (le rang dans la table des caractères, son unicode) décimal 8364 (pour vérifier, taper ord("€") puisque Python est en UTF-8), on note U+8364. En tapant bin(8364) python indique 0b10000010101100, la valeur binaire de 8364. On découpe en 6 en partant de la droite:10 000010 101100, on a donc besoin de trois octets en UTF-8 pour coder €: 11100010 10000010 10101100 soit en haxadécimal E2 82 AC...révisez ! On peut faire tout cela sans l'aide de Python ! (sinon on tape hex(0b111000101000001010101100))

Cette norme permet donc d’être rapide pour les alphabets courants. Elle présente le défaut de ne pas pouvoir aller directement chercher le 10ème caractère d’une phrase puisque le nombre d’octets par lettre est variable. L’UTF-16 est codé sur 4 octets ou 2 octets en fonction du code du caractère (je ne donne pas les détails pour savoir comment on sait que l’on doit en lire 2 ou 4). La norme UTF-32 utilise elle 32 bits en permanence. Cela consomme bien plus de mémoire mais permet de trouver très rapidement le xème caractère d’une chaîne de caractères.

Python est en UTF-8, vous pouvez donc reprendre le programme précédent et aller au-delà de 128.

Sur une page HTML, pour indiquer l’encodage utiliser et permettre au navigateur de la lire correctement, on insère la ligne suivante dans l’élément head :

<meta http-equiv="content-type" content="text/html; charset=utf-8" />
 

Python et les chaînes de caractères

Il faut surtout savoir que les chaînes de caractères sont des tuples (nous verrons cela plus tard, une sorte de liste non modifiable...ça c'est important).
chaine="bonjour"
print(chaine[0]) #va afficher "b"
print(chaine[3:]) #va afficher "jour"

En Ascii il existe certains caractères spéciaux comme \n (pour le retour à la ligne) et \t(tabulation). A noter que l’on peut aussi utiliser les 3 guillemets pour saisir des chaines avec des retours à la ligne. Par exemple

chaine= """un
deux
trois"""
print(chaine)
va afficher
un
deux
trois

Les objets str (strings) ont aussi leurs méthodes et vous en coderez vous même quelques unes. Il est quand même intéressant de les connaître car leur execution sera plus rapide que votre code. Comme il s’agit de méthodes appliquées à l’objet str, on appelle ces méthodes en mettant un point après la variable string. Soit par exemple chaine= "Bonjour", testez les commandes ci-dessous

print(chaine.upper())
print(chaine.lower())
print(chaine[0].upper+chaine[ 1:]
print(chaine.capitalize())
print(chaine.split(", ")
print(chaine.find("jo")
renvoie l’indice du début de trouvé ou -1 si pas trouvé
print(chaine.replace("jo" , "oj")
print(chaine.count("jo"))
liste_chaine = ["C", "H", "A", "I", "N","E"]
print(", ".join(liste_chaine))
donne "C, H, A, I, N, E"
print(" ".join(liste_chaine))
donne "C H A I N E"
print("".join(liste_chaine))
donne "CHAINE"

Exercices

  1. a) Ecrire une fonction qui renvoie un booléen pour indiquer que le texte est en minuscule. Idem avec majuscule. Conseil, commencer par une fonction pour un seul caractère.
    b) Ecrire une fonction qui convertit un texte en majuscule et une pour convertir en minuscule

  2. a) Ecrire une fonction qui indique si un caractère (variable de type char) est un chiffre ou autre.
    b) Utiliser a) pour indiquer si une chaîne est un nombre entier naturel. On pourrait améliorer cela pour indiquer si c'est un nombre décimal...

  3. a)Ecrire une fonction chercher(chaine,sous_chaine) qui recherche si une sous-chaîne est dans une chaine sans utiliser 'in' et renvoie un booléen. ('jo' est unes sous-chaine de 'bonjour' puisque 'jo' est dans 'bonjour')
    b)Améliorer le programme précédent en renvoyant une liste avec la position des sous-chaînes trouvées.
    c)Ecrire une fonction qui supprime un sous chaine d'une chaine, n fois: supprime(chaine,sous-chaine,n). Avec n=-1 si l'on veut tout supprimer.
    d)Ecrire une fonction qui permute deux sous-chaînes permute(chaine,sc1,sc2) et renvoie la nouvelle chaîne.

  4. Définissez une fonction inverse(ch) qui inverse l’ordre des caractères d’une chaîne quelconque et renvoie la chaîne inversée.

  5. Code de César. Le code de César est un mode de cryptage avec clé très simple. On code un texte en décalant tous les caractère d'un certain nombre de rangs donné par la clé. Par exemple, avec une clé de 3, le A devient D et le Z devient C. Ecrire une fonction cesar(chaine,cle) qui retourne la chaîne codée. Ce code est-il facile à cracker ?

  6. On peut facilement lire un texte dont l'ordre des lettres de chaque mot est mélangé mais dont on garde la première est dernière lettre en place. Coder une fonction texte_transformé(chaine) qui réalise cela. Pour mélanger les lettres, on utilisera random.shuffle(liste) de la bibliothèque random. Bien évidemment, il sera plus courageux de ne pas utiliser la commande shuffle mais uniquement randint....

  7. Trouver en expliquant la valeur binaire et hexadécimale du codage UTF-8 de "é", avec la méthode indiquée dans le cours. Est-il surprenant que la valeur scalaire (le rang dans la table utf-8) soit entre 128 et 255? Avec quelle norme le "é" a-t-il donc fait son apparition?

  8. Un caractère a pour code UTF-8 en hexadécimal EFBFBD. Je veux faire afficher ce caractère par python, il me faut donc la valeur scalaire décimale qui lui correspond. (attention il ne s'agit pas de convertir EFBFBD en décimal !)

Android

De la programmation pour pc à la programmation pour téléphone.

A finir

Pas eu le temps de tout faire.....