Les encodages de texte expliqués : UTF-8, Base64 et encodage d’URL

Mis à jour :

Les ordinateurs stockent et envoient des octets, pas des lettres. Chaque fois qu’un texte est enregistré, envoyé ou placé dans une adresse web, il faut décider quels octets représentent quels caractères, et parfois réécrire les octets eux-mêmes pour qu’ils arrivent intacts. Trois encodages font l’essentiel de ce travail : UTF-8 transforme les caractères en octets, Base64 transforme n’importe quels octets en lettres et chiffres ordinaires, et l’encodage-pourcent rend un texte sûr à l’intérieur d’une URL.

Cette dernière partie de la série explique chacun d’eux avec des exemples vérifiables octet par octet, et les relie aux problèmes vus dans les parties sur le JSON et le CSV : la marque d’ordre des octets et les accents qui deviennent ã.

Caractères, points de code et octets

Unicode attribue à chaque caractère un numéro, appelé point de code et écrit U+ suivi de chiffres hexadécimaux : A est U+0041, é est U+00E9, € est U+20AC et l’émoji 😀 est U+1F600. La plage va de U+0000 à U+10FFFF. Un encodage décide comment ces numéros sont stockés en octets.

UTF-8, défini dans la RFC 3629 (norme Internet depuis novembre 2003), utilise d’un à quatre octets par caractère. Les 128 caractères ASCII gardent leur octet unique, si bien qu’un texte anglais sans accents est identique en ASCII et en UTF-8 ; les autres caractères prennent deux, trois ou quatre octets :

UTF-8 est aujourd’hui le choix par défaut presque partout : W3Techs l’a trouvé sur 99,1 % des sites web dont il a pu identifier l’encodage en octobre 2026. D’autres encodages existent pourtant encore à l’intérieur des logiciels. Les chaînes JavaScript, par exemple, sont stockées en UTF-16, en unités de 16 bits, et MDN précise qu’un caractère au-delà de U+FFFF en occupe deux. C’est pourquoi le même émoji compte pour 1 caractère à l’écran, 2 dans la longueur JavaScript et 4 octets en UTF-8, et pourquoi les limites mesurées en caractères et en octets coïncident rarement.

La marque d’ordre des octets

La marque d’ordre des octets (BOM), U+FEFF, peut figurer tout au début d’un fichier. En UTF-8, ce sont toujours les trois octets EF BB BF. UTF-8 n’a pas d’ordre des octets à indiquer : elle n’y sert que de signature pour dire que le fichier est en UTF-8. Le Consortium Unicode la déconseille lorsqu’un protocole ou un logiciel attend des caractères précis au début du fichier.

Les deux parties précédentes de la série la rencontrent par des côtés opposés. Un JSON envoyé sur le réseau ne doit pas commencer par elle, et JSON.parse de JavaScript rejette un texte qui en contient une. Excel, au contraire, en a besoin pour ouvrir correctement un CSV en UTF-8 par double-clic. L’ajouter ou non dépend du logiciel qui lira le fichier.

Base64 : n’importe quels octets en texte

Certains endroits n’acceptent que du texte : le corps d’un e-mail, une chaîne JSON, un attribut HTML. Base64, défini dans la RFC 4648 (octobre 2006), permet à n’importe quels octets, y compris une image ou un PDF, d’y passer. Il prend l’entrée trois octets (24 bits) à la fois et écrit chaque groupe sous forme de quatre caractères d’un alphabet de 64 : A–Z, a–z, 0–9, + et /. Quand le dernier groupe est incomplet, = le complète. Voici les vecteurs de test de la RFC :

Quatre caractères pour trois octets : Base64 est plus gros d’un tiers que l’original, et un fichier de 3 000 000 d’octets devient 4 000 000 de caractères. L’e-mail (MIME) coupe en plus le Base64 en lignes de 76 caractères au maximum, ce qui ajoute encore un peu.

Base64 est un encodage, pas un chiffrement. N’importe qui peut le décoder, sans clé : il ne protège rien. Si un mot de passe ou un jeton n’a l’air illisible que parce qu’il est en Base64, il n’est pas protégé.

Le texte doit devenir des octets avant d’être encodé en Base64 : le résultat dépend donc de l’encodage du texte. La lettre é donne w6k= à partir de ses deux octets UTF-8, mais 6Q== à partir de son unique octet en Latin-1. web.dev souligne que la fonction btoa() du navigateur n’accepte que les caractères qui tiennent sur un octet et renvoie une erreur pour les autres, comme € ; il faut d’abord convertir le texte en octets UTF-8. L’outil Base64 de nTools encode le texte en UTF-8 et, au décodage, indique si les octets étaient en UTF-8 ou en Windows-1252.

Encodeur / décodeur Base64

base64url : la version pour les adresses web

Deux des caractères de Base64 posent problème hors du texte ordinaire. Dans une URL, + peut être lu comme une espace et / sépare les segments du chemin ; dans un nom de fichier, / est interdit. La RFC 4648 définit donc un second alphabet, sûr pour les URL et les noms de fichiers, souvent appelé base64url, qui utilise - et _ à la place. Les spécifications qui l’emploient peuvent aussi omettre le remplissage =, ce que la RFC 4648 permet quand elles le précisent explicitement.

Les JSON Web Tokens en sont l’exemple le plus connu. La RFC 7515 définit leur encodage comme du base64url sans aucun = final ni saut de ligne : c’est pourquoi les parties d’un jeton peuvent contenir - et _, mais jamais +, / ni =. Un décodeur qui ne connaît que le Base64 standard rejette ces chaînes ; l’outil nTools en fait partie, remplacez donc - par + et _ par / avant de décoder.

L’encodage-pourcent : du texte dans une URL

Une URL ne peut contenir qu’un ensemble limité de caractères ASCII, et certains ont un rôle : / sépare le chemin, ? ouvre la requête, & sépare les paramètres, # ouvre le fragment. La RFC 3986 (janvier 2005, norme Internet) en fixe les règles. Les lettres, les chiffres et - . _ ~ peuvent toujours être utilisés tels quels. Les caractères qui ont un rôle sont encodés quand ils font partie d’une valeur et non d’un séparateur, et tout octet hors de l’ensemble autorisé s’écrit % suivi de deux chiffres hexadécimaux. Le texte est d’abord converti en UTF-8 : un caractère hors ASCII devient donc plusieurs codes % :

Encodez les valeurs que vous placez dans une URL, pas l’adresse entière : encoder https://example.com/?q=1 comme une seule valeur transforme ses : / ? et = en codes, ce qui est correct quand l’adresse est elle-même un paramètre d’une autre URL, et faux quand elle doit servir de lien. La fonction encodeURIComponent() de JavaScript fait exactement cet encodage par valeur et, comme l’indique MDN, laisse aussi ! ' ( ) et * tels quels. L’outil URL de nTools l’utilise.

Encodeur / décodeur URL

Un + ou %20 ?

Les formulaires HTML envoient leurs données dans un format un peu différent, application/x-www-form-urlencoded, défini par le standard URL du WHATWG. Une espace y est écrite +, si bien qu’une recherche de a b&c=d est envoyée sous la forme q=a+b%26c%3Dd. Ailleurs dans une URL, + n’est qu’un signe plus.

Cela explique une confusion fréquente : décoder a+b%20c avec un décodeur d’URL général donne a+b c, car seul %20 y est une espace ; un décodeur de formulaire donne a b c. Choisissez le décodeur qui correspond à l’origine du texte. MDN suggère de remplacer %20 par + après encodeURIComponent() quand vous avez besoin du format de formulaire.

Le double encodage

La RFC 3986 avertit qu’une chaîne ne doit pas être encodée ou décodée en pourcent plus d’une fois. Quand cela arrive, le % de chaque code est de nouveau encodé en %25 :

Des séquences comme %2520 ou %25C3%25A9 dans une adresse indiquent qu’un texte déjà encodé a été encodé une seconde fois. Décodez une fois, vérifiez le résultat et n’encodez que les parties qui en ont besoin.

Lequel vous faut-il ?

SituationÀ utiliser
Enregistrer ou envoyer du texte : fichiers, pages web, JSON, CSVUTF-8
Mettre des octets, comme une image ou un fichier, dans du texte : JSON, e-mail, HTMLBase64
Du Base64 dans une URL, un nom de fichier ou un jetonbase64url
Une valeur dans une URL : un terme de recherche, un paramètre, un segment de cheminEncodage-pourcent
Les données envoyées par un formulaire HTMLEncodage de formulaire (espaces en +)
Garder des données secrètesAucun de ceux-ci : utilisez le chiffrement

Questions fréquentes

Base64 est-il une forme de chiffrement ?

Non. C’est un encodage réversible que tout le monde peut décoder sans clé. Il permet aux données de voyager sous forme de texte, pas d’échapper à la lecture.

Pourquoi mon Base64 diffère-t-il de celui d’un autre outil ?

En général parce que le texte a été converti en octets avec un autre encodage, comme le Latin-1 au lieu de l’UTF-8, parce qu’un outil utilise base64url ou omet le remplissage =, ou parce que l’un des deux ajoute des sauts de ligne.

Pourquoi un émoji compte-t-il pour deux caractères ?

Beaucoup de logiciels, dont JavaScript, comptent des unités UTF-16 de 16 bits, et un émoji comme 😀, au-delà de U+FFFF, en demande deux. En UTF-8, il occupe quatre octets.

Faut-il enregistrer les fichiers en UTF-8 avec BOM ?

Seulement quand le logiciel qui lit le fichier en a besoin, comme Excel avec les fichiers CSV. Pour le JSON et la plupart des fichiers web, enregistrez en UTF-8 sans BOM.

Pourquoi mon lien contient-il %2520 ?

Il a été encodé deux fois : %20, une espace, a été encodé de nouveau et son % est devenu %25. Décodez-le une fois et utilisez le résultat.

Les encodeurs nTools envoient-ils mon texte ?

Non. L’encodage et le décodage se font dans votre navigateur, et le texte n’est envoyé nulle part.

Partie précédente ← Les fichiers CSV expliqués : séparateurs, guillemets, encodage et Excel

Références

  1. RFC 3629 — UTF-8, a transformation format of ISO 10646
  2. Unicode Consortium — FAQ: UTF-8, UTF-16, UTF-32 & BOM
  3. W3Techs — Usage statistics of character encodings for websites
  4. MDN — UTF-16 (glossary)
  5. RFC 8259 — The JavaScript Object Notation (JSON) Data Interchange Format
  6. Microsoft Support — Opening CSV UTF-8 files correctly in Excel
  7. RFC 4648 — The Base16, Base32, and Base64 Data Encodings
  8. web.dev — The nuances of base64 encoding strings in JavaScript
  9. RFC 7515 — JSON Web Signature (JWS)
  10. RFC 3986 — Uniform Resource Identifier (URI): Generic Syntax
  11. WHATWG — URL Standard
  12. MDN — encodeURIComponent()

Guides associés