Aller au contenu principal

Échappement JSON

L’échappement JSON réécrit les caractères qui mettraient sinon fin à une chaîne ou la corrompraient. La RFC 8259 rend deux échappements obligatoires — " et \ — puis ajoute cinq échappements de contrôle nommés, un échappement de barre oblique optionnel, et la forme universelle \uXXXX. Ce guide couvre chaque échappement, les paires de substitution derrière les émojis, et le moment où l’échappement aide ou dessert.

100 % local

Échappement JSON en clair

Chaque chaîne JSON vit entre deux guillemets doubles ; le format a donc besoin d’un moyen de placer un guillemet double dans une chaîne sans la terminer — et d’un moyen d’insérer une barre oblique inverse dans une chaîne sans démarquer un échappement non voulu. La réponse, c’est l’échappement : une barre oblique inverse placée devant un caractère change la signification de ce caractère pour le parseur, transformant une marque structurelle en donnée ordinaire.

Le dispositif est petit et fermé. La RFC 8259 définit exactement neuf échappements à deux caractères plus une forme extensible, \uXXXX, et rien d’autre : une barre oblique inverse suivie de tout autre caractère est une erreur de syntaxe, pas un passage toléré. Cet aspect fermé est un atout — les bugs d’échappement sont toujours reproductibles, car un parseur conforme reconnaît la séquence ou rejette le document.

Ce guide parcourt la table d’échappement complète, puis les deux parties que les gens trouvent les plus difficiles : \uXXXX et les paires de substitution qu’il exige pour les émojis, ainsi que le compromis de taille de l’échappement du texte non ASCII. Chaque exemple est copiable, et les outils liés s’exécutent dans votre navigateur : vous pouvez faire des allers-retours sur vos propres chaînes en local, sans rien installer.

Le moyen le plus rapide de voir l’échappement à l’œuvre est de regarder un parseur le résoudre — le formateur JSON affiche le résultat sans échappement à côté de votre saisie pendant qu’il réindente un document.

L’échappement est un chapitre de la grammaire ; l' aide-mémoire de syntaxe JSON condense le reste des règles — structure, espacement, nombres — sur une seule page de référence.

Les deux échappements incontournables

Dans une chaîne, un guillemet double littéral doit s’écrire " et une barre oblique inverse littérale \. Ces deux-là sont obligatoires pour tout producteur, car sans eux un parseur ne peut pas dire où une chaîne se termine ni où un échappement commence — aucune autre graphie n’est disponible. Tout autre échappement de la grammaire est optionnel au sens où son caractère aurait pu être écrit littéralement ; ces deux-là n’ont aucune forme littérale dans une chaîne.

La barre oblique est le cas particulier : \/ est légal et signifie /, mais la barre oblique littérale n’a jamais besoin d’être échappée. Ce raccourci existe pour une raison historique — l’insertion de JSON dans des blocs HTML <script>, où la séquence </script> dans une chaîne pourrait fermer prématurément la balise englobante. Certains générateurs échappent encore chaque barre oblique par prudence ; le prix est un document un peu plus gros, un peu plus bruité.

Échappements obligatoires et optionnels dans un même document

{
  "path": "C:\\temp\\notes.txt",
  "line": "she said \"ship it\"",
  "html": "<\\/script>"
}

Ce que restitue un parseur

path:  C:\temp\notes.txt
line:  she said "ship it"
html:  </script>

Les cinq caractères de contrôle nommés

Un texte peut légalement contenir des caractères de contrôle inférieurs à U+0020 — tabulation, saut de ligne, retour chariot et compagnie — mais un caractère de contrôle brut dans une chaîne JSON n’est pas interopérable : il casse l’outillage orienté lignes et certains parseurs tout court. La norme exige donc que les caractères de contrôle soient échappés, et en nomme cinq : \b retour arrière (U+0008), \f saut de page (U+000C), \n saut de ligne (U+000A), \r retour chariot (U+000D) et \t tabulation horizontale (U+0009). Tout autre caractère de contrôle doit prendre la forme \u00XX, comme \u0001.

Notez ce que cela signifie pour les sauts de ligne en particulier : un document formaté possède de vrais sauts de ligne entre les tokens, mais un saut de ligne dans une valeur de chaîne est toujours les deux caractères \n. Une valeur de chaîne occupe une seule ligne dans le fichier même quand son contenu est multi-lignes — l’un des points de confusion les plus fréquents à la lecture d’un JSON formaté.

ÉchappementPoint de codeCaractère
\bU+0008retour arrière
\tU+0009tabulation horizontale
\nU+000Asaut de ligne (nouvelle ligne)
\fU+000Csaut de page
\rU+000Dretour chariot
\u00XXU+0000–U+001Ftout autre caractère de contrôle

Une note de trois lignes stockée dans une seule chaîne JSON

{
  "note": "first line\nsecond line\ttabbed"
}

Son contenu après analyse

first line
second line	tabbed

\uXXXX : n’importe quel point de code, exactement quatre chiffres hexadécimaux

L’échappement \u écrit un point de code sous la forme d’exactement quatre chiffres hexadécimaux : \u00e9 est é, \u4f60 est 你, \u0041 est le même A que vous auriez pu taper littéralement. Les parseurs traitent la forme échappée et la forme littérale comme identiques — un document qui échappe chaque caractère non ASCII et un document qui n’échappe que les deux obligatoires décodent vers exactement les mêmes chaînes. L’échappement est une décision de transport, pas une différence de données.

Les quatre chiffres plafonnent la forme aux points de code jusqu’à U+FFFF, le plan multilingue de base. Tout ce qui est au-dessus — émojis, écritures historiques, la plupart des symboles — ne tient pas dans un seul échappement \u, et cette limitation est exactement là où les paires de substitution entrent en scène.

Deux graphies d'une même valeur

{
  "city": "\u5317\u4eac",
  "note": "escaped form"
}
{
  "city": "北京",
  "note": "literal UTF-8"
}

Les deux s'analysent en la même chaîne

city: 北京

(le fichier échappé est en ASCII pur ;
le fichier littéral est plus petit, mais multi-octet)

Plan astral : paires de substitution et substituts isolés

En interne, JavaScript et la notation \u travaillent en unités de code UTF-16. Les caractères au-dessus de U+FFFF s’écrivent en paire : un substitut haut de U+D800–U+DBFF suivi d’un substitut bas de U+DC00–U+DFFF. La tête souriante U+1F600 devient donc \ud83d\ude00 — douze caractères sources pour un émoji. Échappez une moitié sans l’autre et vous obtenez un substitut isolé : la RFC 8259 §8.2 signale ces chaînes comme imprévisibles à interpréter, et les producteurs interopérables n’en émettent tout simplement jamais.

Les paires de substitution expliquent aussi pourquoi la longueur des chaînes ment. JavaScript indique que la longueur de "😀" est 2, parce qu’il compte des unités de code UTF-16 plutôt que des caractères — un détail qui compte quand vous découpez, tronquez ou validez du texte échappé, et la raison d’être des bibliothèques conscientes des graphèmes.

Un émoji, deux unités de code, douze caractères échappés

{
  "mood": "\ud83d\ude00"
}
{
  "mood": "😀"
}

Les deux s'analysent en un même caractère unique

mood: 😀  (U+1F600 — length 2 in UTF-16 units)

Le coût de l’échappement : lisibilité et taille

L’échappement échange la lisibilité contre la sûreté. Un document qui échappe chaque caractère non ASCII survit à n’importe quel canal 7 bits — passerelles qui retirent le huitième bit de chaque octet, systèmes de messagerie anciens, journaux configurés en ASCII pur — au prix d’être presque illisible pour les humains. C’était la posture par défaut de beaucoup de premières bibliothèques JSON ; les valeurs par défaut modernes préfèrent l’UTF-8 littéral et n’échappent que ce que la grammaire exige.

Le coût en taille se prédit à partir du point de code, car chaque échappement \uXXXX coûte exactement 6 octets, quel que soit ce qu’il encode. Supprimer les échappements d’un document à dominante CJK le divise à peu près par deux ; le texte arabe et cyrillique se réduit d’environ deux tiers ; et échapper de l’ASCII pur le multiplie par six — voilà pourquoi les payloads ASCII échappés des systèmes anciens paraissent bien plus gros que leur contenu réel.

TextePoint de codeUTF-8 littéralForme échappéeTaille échappée
aU+00611 octet\u00616 octets
بU+06282 octets\u06286 octets
аU+04302 octets\u04306 octets
你U+4F603 octets\u4f606 octets
😀U+1F6004 octets\ud83d\ude0012 octets

Retrait des échappements, allers-retours et cas où les conserver

Le retrait des échappements n’est pas une opération distincte que vous devriez écrire : chaque parseur conforme l’effectue pendant le décodage, si bien qu’analyser "\u0041" et analyser "A" produit des chaînes identiques. La direction inverse — choisir quoi échapper quand on produit du JSON — est une affaire de goût entre bibliothèques, et les seules règles dures y sont les deux échappements obligatoires plus l’exigence des caractères de contrôle.

Gardez l’échappement agressif pour ses deux cas d’usage honnêtes : survivre à des canaux auxquels on ne peut pas confier l’UTF-8, et les diffs où chaque différence d’encodage invisible doit devenir visible. Partout ailleurs, l’UTF-8 littéral avec un minimum d’échappements est plus petit, plus rapide à parcourir et plus facile à relire. Si un document reçu semble sur-échappé, analysez-le et resérialisez-le une fois — la sortie se débarrasse de chaque échappement optionnel tout en restant exactement les mêmes données.

Questions fréquentes

Est-il sûr de coller des chaînes sensibles dans les outils JSON de ce site ?

Oui — le formateur, le validateur et le minifieur liés depuis ce guide s’exécutent tous localement dans votre navigateur. Il n’y a aucune étape d’envoi : l’analyse et la resérialisation se produisent en JavaScript dans l’onglet, le panneau Network n’affiche aucune requête transportant votre texte, et la Content-Security-Policy du site bloque les connexions sortantes comme seconde ligne de défense. Vos chaînes ne quittent jamais la machine où vous les avez tapées.

Comment mettre un émoji dans une chaîne JSON ?

Deux façons : collez l’émoji littéralement — 😀 est du JSON UTF-8 valide — ou écrivez sa paire de substitution, \ud83d\ude00. Les deux se décodent vers le même caractère. La forme échappée mérite d’être connue parce que certains canaux et outillages anciens mutilent les émojis littéraux, et parce que les messages d’erreur, les logs et les diffs vous montrent souvent la paire plutôt que la tête.

Qu’est-ce qu’un substitut isolé et pourquoi casse-t-il les parseurs ?

Un substitut haut (\ud800–\udbff) ou bas (\udc00–\udfff) écrit sans son partenaire. Seul, il n’encode rien : la RFC 8259 §8.2 qualifie d’imprévisibles à interpréter les chaînes qui en contiennent. Les implémentations varient — certaines les acceptent, d’autres les remplacent par U+FFFD, d’autres lèvent une erreur — n’émettez donc jamais une moitié de paire, et traitez un substitut isolé dans des données entrantes comme une corruption.

Pourquoi \/ est-il un échappement valide alors que / n’a pas besoin d’être échappé ?

Il existe pour insérer du JSON dans du HTML : dans un bloc <script>, la séquence littérale </script> dans une chaîne terminerait le bloc prématurément, alors les générateurs échappent chaque barre oblique en \/ pour casser le motif. La grammaire accepte tout aussi bien la forme non échappée. Sauf si vous insérez du JSON dans du HTML, \/ est du bruit pur — et les minifieurs le retirent volontiers.

L’échappement change-t-il les données que mon API reçoit ?

Non. Les échappements sont des graphies, pas des valeurs : "\u00e9" et "é" se décodent en la chaîne identique, donc tout parseur conforme délivre le même texte Unicode dans les deux cas. L’échappement ne change que l’apparence du fichier et sa taille — voilà pourquoi une réponse sur-échappée est laide mais inoffensive, et pourquoi vous pouvez la normaliser en analysant puis en resérialisant.

De combien un JSON est-il plus petit sans les échappements \u ?

Cela dépend de l’écriture, car chaque \uXXXX coûte 6 octets tandis que l’UTF-8 littéral coûte 1 octet pour l’ASCII, 2 pour les lettres arabes ou cyrilliques, 3 pour le CJK et 4 pour les émojis. Supprimer les échappements d’un document chinois le divise à peu près par deux ; l’arabe ou le cyrillique se réduit d’environ deux tiers ; échapper de l’ASCII le multiplie par six. La forme échappée est toujours égale ou plus grande.

Où puis-je lire les normes citées ici ?

  • RFC 8259 — Le format d’échange de données JavaScript Object Notation (JSON)