Échapper une chaîne JSON : caractères, stringify et pièges
Échapper une chaîne JSON, c’est transformer un texte quelconque en une chaîne qui peut se loger sans danger dans un document JSON sous forme de littéral de chaîne. Une poignée de caractères (le guillemet double, la barre oblique inverse, et les caractères de contrôle comme le saut de ligne et la tabulation) portent un sens structurel ou sont tout simplement illégaux à l’intérieur d’une chaîne JSON ; chacun est donc remplacé par une séquence d’échappement sûre telle que \", \\ ou \n. Si vous le faites mal, votre payload cesse d’être analysable.
Vous y êtes confronté en permanence : imbriquer un objet JSON dans un autre comme champ de type chaîne, coller un extrait de code multiligne dans une valeur de configuration, ou construire à la main un corps de requête REST pour curl. Ce guide couvre précisément quels caractères doivent être échappés, dissipe la confusion entre échappement et JSON.stringify, parcourt l’imbrication JSON-dans-JSON et les échappements Unicode, et liste les pièges qui cassent silencieusement les payloads. Si vous voulez simplement échapper quelque chose tout de suite, notre outil Échappement JSON le fait dans le navigateur ; mais lisez la suite pour comprendre pourquoi il fonctionne ainsi.
Qu’est-ce que l’échappement de chaînes JSON ?
L’échappement de chaînes JSON est le processus de conversion d’une chaîne brute en une forme sûre à intégrer dans un document JSON. JSON réserve un petit ensemble de caractères qui portent un sens structurel : le guillemet double " délimite une chaîne, et la barre oblique inverse \ amorce une séquence d’échappement. S’y ajoutent les caractères de contrôle en dessous de U+0020 (sauts de ligne, tabulations, retours chariot), qui n’ont pas le droit d’apparaître littéralement à l’intérieur d’une chaîne JSON. L’échappement remplace chacun d’eux par une séquence sûre, de sorte que la chaîne résultante s’analyse proprement partout.
Quand en avez-vous réellement besoin ? Quelques situations reviennent sans cesse :
- JSON-dans-JSON : une enveloppe de webhook, un message Kafka ou un journal d’audit stocke un corps de requête comme champ de type chaîne, donc le JSON interne doit être échappé avant de pouvoir être affecté.
- Configuration écrite à la main : déposer un script shell multiligne, une requête SQL ou un extrait de code dans une seule valeur JSON revient à transformer chaque saut de ligne en
\n. - Corps de requêtes REST : construire à la main un corps JSON pour
curlou un client HTTP, où les guillemets et les sauts de ligne doivent survivre au shell et au réseau. - Encodage sûr pour les journaux : écrire du contenu fourni par l’utilisateur dans une ligne de journal structurée sans qu’un guillemet ou un saut de ligne injecté corrompe le format.
Un mot rapide sur l’ordre des opérations. Si vous partez d’un JSON désordonné ou non fiable, validez-le d’abord pour échapper quelque chose de bien formé : collez-le dans le Formateur JSON pour le mettre en forme et le vérifier, puis échappez le résultat propre. Échapper du n’importe quoi ne donne que du n’importe quoi échappé.
Quels caractères doivent être échappés en JSON
La spécification JSON définit une liste précise et courte. Sept caractères disposent d’un échappement dédié à deux caractères, et tout le reste en dessous de U+0020 retombe sur un échappement Unicode \uXXXX. Voici l’ensemble complet des caractères d’échappement JSON :
| Caractère | Échappé en | Notes |
|---|---|---|
" (U+0022) | \" | Délimiteur de chaîne |
\ (U+005C) | \\ | Amorce d’échappement (le cas de la barre oblique inverse JSON) |
| saut de ligne (U+000A) | \n | |
| retour chariot (U+000D) | \r | |
| tabulation (U+0009) | \t | |
| retour arrière (U+0008) | \b | |
| saut de page (U+000C) | \f | |
| autres contrôles < U+0020 | \uXXXX | ex. U+0000 → \u0000 |
Ce qui n’a pas besoin d’être échappé est tout aussi important. La barre oblique / est un caractère parfaitement normal (l’échapper est facultatif et n’est utile que dans un cas précis traité plus bas). Les guillemets simples n’ont jamais besoin d’échappement car JSON ne les utilise pas comme délimiteurs. Et tout caractère imprimable à partir de U+0020, y compris tous les caractères UTF-8 multi-octets comme é, 日 ou 😀, est valide tel quel.
Voici la différence rendue concrète. L’entrée brute à gauche, le littéral de chaîne JSON échappé à droite :
Input:
She said "hello" then left.
Escaped:
"She said \"hello\"\tthen left."
Les guillemets doubles sont devenus \" et la tabulation est devenue \t. La chaîne peut désormais être déposée sans danger dans n’importe quel analyseur JSON, ligne de journal ou corps de requête.
Échappement JSON vs JSON.stringify : quelle différence ?
C’est le point que la plupart des tutoriels passent sous silence, et il sème la confusion chez beaucoup de gens. L’échappement et JSON.stringify ne sont pas deux opérations différentes ; ce sont deux points de vue sur la même.
JSON.stringify(value) sérialise n’importe quelle valeur JavaScript en sa représentation textuelle JSON. Lorsque cette valeur se trouve être une chaîne, la sérialiser revient à l’entourer de guillemets doubles et à échapper les caractères spéciaux à l’intérieur. C’est exactement l’échappement JSON. Ainsi JSON.stringify("a\tb") renvoie la chaîne de sept caractères "a\tb", guillemets compris.
La question pratique est de savoir si vous voulez ces guillemets extérieurs. Cela correspond directement à l’option Entourer de guillemets doubles de l’outil Échappement JSON :
| Mode | Sortie pour l’entrée a"b | Quand l’utiliser |
|---|---|---|
| Entourage activé | "a\"b" | Un littéral de chaîne JSON complet, identique à JSON.stringify. Affectez-le à une variable ou collez-le après un deux-points. |
| Entourage désactivé | a\"b | Juste le corps échappé, sans guillemets autour. Utilisez-le quand vous tapez vous-même les guillemets dans un document JSON. |
Donc si vous avez cherché « json stringify » et atterri ici : stringify d’une chaîne = échappement avec entourage activé. La forme sans guillemets est la même chose dont on aurait retiré les guillemets extérieurs.
Comment échapper une chaîne pour JSON dans le code
La règle d’or : ne bricolez jamais une chaîne d’appels replace() à la main. Tous les langages courants livrent un sérialiseur JSON qui gère correctement les guillemets, les barres obliques inverses, les caractères de contrôle et l’Unicode. Tournez-vous vers lui.
JavaScript
const text = 'She said "hi"\nthen left.';
const escaped = JSON.stringify(text);
console.log(escaped);
// "She said \"hi\"\nthen left."
JSON.stringify sur une chaîne vous donne le littéral complet, entre guillemets. Vous ne voulez que le corps ? Retirez le premier et le dernier caractère : JSON.stringify(text).slice(1, -1).
Python
import json
text = 'She said "hi"\nthen left.'
print(json.dumps(text))
# "She said \"hi\"\nthen left."
print(json.dumps(text, ensure_ascii=False))
# "She said \"hi\"\nthen left." (non-ASCII kept as UTF-8)
json.dumps utilise par défaut ensure_ascii=True, qui échappe chaque caractère non-ASCII en \uXXXX, soit le même comportement que le mode ASCII-safe de l’outil. Passez ensure_ascii=False pour conserver l’UTF-8 brut.
PHP
<?php
$text = "café \"quoted\"\nline";
echo json_encode($text);
// "caf\u00e9 \"quoted\"\nline" (default escapes non-ASCII to \uXXXX)
echo json_encode($text, JSON_UNESCAPED_UNICODE);
// "café \"quoted\"\nline"
json_encode échappe par défaut à la fois les caractères non-ASCII et les barres obliques. Ajoutez JSON_UNESCAPED_UNICODE pour garder les accents lisibles, et JSON_UNESCAPED_SLASHES pour laisser / tranquille.
Go et Java
En Go, json.Marshal(text) renvoie les octets échappés et entre guillemets :
b, _ := json.Marshal(`a "quoted" line`)
// b == `"a \"quoted\" line"`
En Java, objectMapper.writeValueAsString(text) de Jackson ou JSONObject.quote(text) d’org.json produisent le même littéral entre guillemets. Quel que soit le langage, appuyez-vous sur la bibliothèque : elle connaît déjà tous les cas limites que vous oublieriez.
Imbriquer du JSON dans du JSON (JSON-dans-JSON)
C’est la raison la plus fréquente pour laquelle les gens échappent du JSON à la main. Une enveloppe de webhook, un enregistrement de file de messages ou un journal d’audit stocke souvent un corps de requête entier comme champ de type chaîne. Pour ce faire, le JSON interne doit d’abord être échappé.
Regardez un petit objet traverser deux couches d’encodage :
1. Inner object: {"a":1}
2. Escaped as a string: "{\"a\":1}"
3. Placed in envelope: {"payload": "{\"a\":1}"}
Chaque " de l’objet interne est devenu \", et le tout a été entouré d’une seule paire de guillemets extérieurs. Le résultat est une unique valeur de chaîne valide que vous pouvez affecter à payload.
Le piège avec une imbrication plus profonde, c’est que les barres obliques inverses se multiplient. Échapper une chaîne déjà échappée échappe aussi ses barres obliques inverses, donc chaque couche les double à peu près : un guillemet interne qui était \" devient \\\" un niveau plus loin, et \\\\\" un niveau encore au-delà. Le JSON-dans-JSON à trois niveaux est vraiment difficile à lire, c’est pourquoi un outil aide. Pour aller dans l’autre sens et extraire l’objet interne de la chaîne, passez-le dans notre outil Déséchappement JSON.
Unicode et échappement \uXXXX
Par défaut, JSON se contente parfaitement d’UTF-8 brut. Un é reste un é, un 日 reste un 日, et le document n’en est que plus lisible. Vous n’avez pas besoin d’échapper le moindre caractère Unicode imprimable.
Alors quand recourir à une sortie ASCII-safe \uXXXX ? Uniquement lorsqu’on ne peut pas faire confiance à un système en aval avec de l’UTF-8 : vieilles passerelles SOAP ou XML, certains pipelines de journalisation, en-têtes d’e-mail, ou fichiers source qui doivent rester en ASCII pur. En mode ASCII-safe, chaque caractère au-dessus de U+007F devient un échappement \uXXXX : café se transforme en caf\u00e9. C’est plus bruyant mais octet pour octet de l’ASCII, et cela se décode vers l’original dans n’importe quel analyseur conforme.
Il y a une subtilité. \uXXXX encode une seule unité de code UTF-16 de 16 bits, mais les caractères en dehors du Plan Multilingue de Base (emoji, écritures rares) ont besoin de 21 bits. JSON les gère avec une paire de substitution (surrogate pair) : deux échappements \uXXXX à la suite. Un visage souriant 😀 (U+1F600) devient \ud83d\ude00. La plupart des sérialiseurs le font pour vous ; le danger vient d’un échappeur écrit à la main qui émet une substitution isolée et non appariée.
Si les paires de substitution et les points de code sont un terrain nouveau pour vous, le Guide UTF-8 vs UTF-16 vs Unicode détaille exactement comment un seul caractère se mappe en octets et en unités de code. C’est le contexte manquant qui explique pourquoi un emoji a besoin de deux échappements.
Déséchappement : relire un JSON échappé
L’échappement a son inverse. Pour retransformer "a\tb" en son texte réel à deux lignes ou tabulé, vous l’analysez : JSON.parse(str) en JavaScript, json.loads(str) en Python. L’analyseur parcourt chaque séquence d’échappement et reconstruit les caractères originaux, paires de substitution comprises.
Quand le déséchappement échoue, l’erreur est presque toujours « invalid escape sequence », et elle a quelques causes habituelles :
- Une barre oblique inverse isolée devant un caractère que JSON ne reconnaît pas comme échappement, comme
\q. - Un échappement inventé tel que
\x41: JSON n’a pas d’échappement hexadécimal\x, il n’utilise que\u. - Un échappement
\utronqué avec moins de quatre chiffres hexadécimaux, comme\u00. - Un guillemet double égaré ou non apparié qui rompt la limite de la chaîne.
Vérifiez que chaque barre oblique inverse amorce l’un des échappements valides (\n \r \t \b \f \" \\ \/ \uXXXX) et que les guillemets sont appariés. Pour les chaînes échappées copiées au milieu d’une ligne de journal, où les guillemets extérieurs ont souvent été laissés de côté, notre outil Déséchappement JSON accepte le corps avec ou sans guillemets autour et le décode dans les deux cas.
Pièges courants de l’échappement JSON
La plupart des payloads cassés se ramènent à l’une de ces six erreurs.
1. Double échappement. Échapper un texte déjà échappé transforme \n en \\n et \" en \\\", de sorte que le consommateur lit une barre oblique inverse-n littérale au lieu d’un saut de ligne. Cela arrive généralement quand un service en amont a déjà échappé la valeur en JSON et que vous l’échappez à nouveau. Déséchappez d’abord pour vérifier l’état actuel, puis échappez exactement une fois.
2. Oublier les guillemets extérieurs. Avec l’entourage désactivé, vous n’obtenez que le corps échappé, pas une chaîne complète. Coller hello \"world\" directement là où une valeur JSON est attendue est invalide parce que les guillemets autour manquent. Soit vous gardez l’entourage activé, soit vous tapez les guillemets vous-même.
3. Sur-échapper le non-ASCII. Activer le mode ASCII-safe alors que le consommateur gère très bien l’UTF-8 ne fait que gonfler la sortie. café devient caf\u00e9 sans raison : plus dur à lire et plus lourd sur le réseau, pour aucun bénéfice. Laissez-le désactivé sauf si un système hérité précis exige de l’ASCII pur.
4. Échapper la barre oblique par réflexe. L’échappement de / ne compte que dans un seul endroit : du JSON inséré à l’intérieur d’une balise HTML <script>, où la sous-chaîne </script> fermerait la balise prématurément, sans égard au contexte JSON. Échapper / en \/ la neutralise. En dehors de ce cas unique, échapper les barres obliques n’ajoute que du bruit ; laissez-le désactivé pour les corps REST, les fichiers de configuration et les payloads de messages.
5. Chaînes de replace bricolées à la main. Un pipeline manuel replace('"', '\\"') oublie presque toujours quelque chose : un caractère de contrôle, un retour arrière, une paire de substitution. Utilisez le sérialiseur du langage, qui couvre toute la spécification.
6. Échapper mais ne jamais déséchapper (ou déséchapper deux fois). Un aller-retour doit s’équilibrer. Échappez une fois à l’entrée, déséchappez une fois à la sortie. Déséchappez deux fois et vous abîmez de vraies barres obliques inverses qui faisaient partie des données.
Une distinction de plus à bien clouer : l’échappement JSON n’est pas l’encodage d’URL ou par pourcentage. Ils résolvent des problèmes différents pour des transports différents, et les mélanger (encoder une valeur par pourcentage puis l’échapper en JSON, ou l’inverse) produit un résultat qu’aucun analyseur ne peut lire proprement. Le Guide encodage et décodage d’URL explique quand l’encodage par pourcentage est le bon outil et en quoi il diffère de ce que fait JSON.
Foire aux questions
Que signifie échapper une chaîne en JSON ?
Cela signifie remplacer les caractères qui portent un sens structurel pour JSON (le guillemet double, la barre oblique inverse, et les caractères de contrôle comme le saut de ligne et la tabulation) par des séquences d’échappement sûres telles que \", \\ et \n. Le résultat peut être intégré comme littéral de chaîne dans un document JSON sans casser l’analyse.
Quels caractères doivent être échappés en JSON ?
Le guillemet double, la barre oblique inverse, le saut de ligne, le retour chariot, la tabulation, le retour arrière et le saut de page reçoivent chacun un échappement dédié, et tout autre caractère de contrôle en dessous de U+0020 devient \uXXXX. Les caractères imprimables et l’UTF-8 multi-octets n’ont pas besoin d’échappement ; la barre oblique est facultative et ne compte qu’à l’intérieur des balises HTML <script>.
L’échappement JSON est-il identique à JSON.stringify ?
Ce sont surtout deux points de vue sur une seule opération. JSON.stringify appliqué à une chaîne l’entoure de guillemets doubles et échappe les caractères spéciaux à l’intérieur, ce qui est exactement l’échappement JSON. Entourage activé = la forme entre guillemets (identique à JSON.stringify) ; entourage désactivé = juste le corps échappé sans les guillemets autour.
Comment échapper une chaîne pour JSON en JavaScript ou Python ?
En JavaScript, utilisez JSON.stringify(str) ; en Python, utilisez json.dumps(str). Appuyez-vous toujours sur la fonction intégrée plutôt que sur une chaîne de replace écrite à la main. Ces fonctions gèrent correctement l’Unicode, les caractères de contrôle et chaque cas limite que vous manqueriez autrement.
Pourquoi mon JSON casse-t-il avec des barres obliques inverses en trop ?
La cause habituelle est le double échappement : échapper un texte déjà échappé, de sorte que \n devient \\n et que le consommateur lit une barre oblique inverse-n littérale au lieu d’un saut de ligne. Déséchappez d’abord la valeur pour vérifier son état réel, puis échappez-la exactement une fois.
Dois-je échapper les barres obliques ou l’Unicode en JSON ?
Ni l’un ni l’autre n’est requis. La / est un caractère normal et n’a besoin d’être échappée que lorsque vous insérez du JSON dans une balise HTML <script>, pour empêcher la séquence </script> de la fermer prématurément. L’Unicode reste en UTF-8 brut par défaut ; n’utilisez \uXXXX que lorsqu’un système en aval ne peut pas gérer l’UTF-8.