Adloun

Hors programme, en lien avec le projet du chapitre

Exercice supplémentaire · niveau 3 (difficile) · NSI (première), chapitre 2 — Flottants, booléens et textes · Unicode dans le détail

Énoncé

Hors programme, en lien avec le projet du chapitre. Écrire deviner_encodage(octets) qui essaie "utf-8" puis "latin-1" et rend le premier qui réussit. Montrer, sur un exemple, que la fonction se trompe toujours dans un cas précis, et proposer un critère supplémentaire.

Corrigé


def deviner_encodage(octets, candidats=("utf-8", "latin-1")):
    """Premier encodage candidat qui decode sans lever d'exception.

    Precondition : aucune. ATTENTION, la valeur rendue est une
    HYPOTHESE, jamais une certitude : voir la discussion.
    """
    for e in candidats:
        try:
            octets.decode(e)
            return e
        except UnicodeDecodeError:
            pass
    return None

>>> deviner_encodage("élève".encode("utf-8"))
'utf-8'
>>> deviner_encodage("élève".encode("latin-1"))
'latin-1'
>>> deviner_encodage(b"\xff\xfe\xfd")
'latin-1'

Ce qui marche. L'ordre des candidats n'est pas arbitraire : de l'UTF-8 valide est rarement du latin-1 plausible, alors que du latin-1 est toujours accepté par le décodeur. On essaie donc le plus exigeant d'abord.

Le cas où la fonction se trompe toujours. La troisième ligne le montre : FF FE FD n'est ni du texte ni rien d'intelligible, et la fonction répond « latin-1 » avec aplomb. La raison est structurelle — latin-1 décode n'importe quelle suite d'octets, ses codes étant tous attribués. Le dernier candidat de la liste sera donc toujours retenu, quoi qu'on lui donne. La fonction ne devine rien : elle élimine.

Un critère supplémentaire, comme le suggère le projet du cours : une fois le décodage réussi, mesurer la vraisemblance du texte obtenu — proportion de caractères imprimables, présence de séquences typiques du mojibake (é, è, ê), fréquence des lettres comparée à celle du français. On passe alors d'un test binaire à un score, et l'on choisit le maximum.

Prolongement honnête : aucun détecteur n'est infaillible, et c'est démontrable. Le même octet E9 est un é en latin-1 et une lettre parfaitement valide dans d'autres tables ISO-8859 ; sans information extérieure, rien ne permet de trancher. C'est bien pourquoi les formats modernes déclarent leur encodage — l'en-tête HTTP, la balise <meta charset>, et l'argument encoding de open.

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.