Come fare l’escape di stringhe JSON: caratteri, stringify, errori
Fare l’escape di una stringa JSON significa trasformare un testo qualsiasi in una stringa che possa stare in sicurezza dentro un documento JSON come stringa letterale. Un piccolo gruppo di caratteri (le virgolette doppie, il backslash e i caratteri di controllo come a capo e tabulazione) porta con sé un significato strutturale oppure è semplicemente illegale dentro una stringa JSON, quindi ciascuno viene sostituito con una sequenza di escape sicura come \", \\ o \n. Sbaglia questo passaggio e il tuo payload smette di essere analizzato.
Ti ci imbatti di continuo: annidare un oggetto JSON dentro un altro come campo stringa, incollare uno snippet di codice multilinea in un valore di configurazione oppure costruire a mano il corpo di una richiesta REST per curl. Questa guida spiega esattamente quali caratteri richiedono l’escape, chiarisce la confusione tra l’escape e JSON.stringify, ripercorre l’annidamento JSON-in-JSON e gli escape Unicode ed elenca gli errori che rompono i payload in silenzio. Se vuoi solo fare l’escape di qualcosa adesso, il nostro strumento Escape JSON lo fa nel browser, ma vale la pena capire perché funziona così.
Cos’è l’escape delle stringhe JSON?
L’escape delle stringhe JSON è il processo che converte una stringa grezza in una forma sicura da inserire dentro un documento JSON. JSON riserva un piccolo insieme di caratteri dal significato strutturale: le virgolette doppie " delimitano una stringa e il backslash \ apre una sequenza di escape. In più, i caratteri di controllo sotto U+0020 (a capo, tabulazioni, ritorni a capo) non possono comparire in modo letterale dentro una stringa JSON. L’escape sostituisce ciascuno di questi con una sequenza sicura, così che la stringa risultante venga analizzata correttamente ovunque.
Quando serve davvero? Alcune situazioni si ripresentano di continuo:
- JSON-in-JSON: un envelope di webhook, un messaggio Kafka o un log di audit memorizza il corpo di una richiesta come campo stringa, quindi il JSON interno deve subire l’escape prima di poter essere assegnato.
- Configurazione scritta a mano: inserire uno script di shell multilinea, una query SQL o uno snippet di codice in un singolo valore JSON significa trasformare ogni a capo in
\n. - Corpi di richieste REST: costruire a mano un corpo JSON per
curlo per un client HTTP, dove virgolette e a capo devono sopravvivere alla shell e al transito sulla rete. - Codifica sicura per i log: scrivere contenuti forniti dall’utente in una riga di log strutturata senza che una virgoletta o un a capo iniettato corrompa il formato.
Due parole sull’ordine delle operazioni. Se parti da un JSON disordinato o non affidabile, validalo prima così fai l’escape di qualcosa di ben formato: incollalo nel Formattatore JSON per stamparlo in modo leggibile e controllarlo, poi fai l’escape del risultato pulito. Fare l’escape di spazzatura ti dà solo spazzatura con l’escape.
Quali caratteri devono ricevere l’escape in JSON
La specifica JSON definisce un elenco preciso e breve. Sette caratteri hanno un escape dedicato di due caratteri e tutto il resto sotto U+0020 ricade su un escape Unicode \uXXXX. Ecco l’insieme completo dei caratteri di escape JSON.
| Carattere | Diventa | Note |
|---|---|---|
" (U+0022) | \" | Delimitatore di stringa |
\ (U+005C) | \\ | Inizio dell’escape (il caso del json escape backslash) |
| a capo (U+000A) | \n | |
| ritorno a capo (U+000D) | \r | |
| tabulazione (U+0009) | \t | |
| backspace (U+0008) | \b | |
| avanzamento modulo (U+000C) | \f | |
| altri controlli < U+0020 | \uXXXX | es. U+0000 → \u0000 |
Ciò che non richiede l’escape è altrettanto importante. La barra / è un carattere del tutto normale (farne l’escape è facoltativo ed è utile solo in un caso ristretto trattato più avanti). Le virgolette singole non richiedono mai l’escape perché JSON non le usa come delimitatori. E ogni carattere stampabile pari o superiore a U+0020 è valido così com’è, inclusi tutti i caratteri UTF-8 multi-byte come é, 日 o 😀.
Ecco la differenza resa concreta. L’input grezzo a sinistra, la stringa JSON con l’escape a destra:
Input:
She said "hello" then left.
Escaped:
"She said \"hello\"\tthen left."
Le virgolette doppie sono diventate \" e la tabulazione è diventata \t. Ora la stringa si può inserire in sicurezza in qualsiasi parser JSON, riga di log o corpo di richiesta.
Escape JSON e JSON Stringify: qual è la differenza?
Questo è il punto che la maggior parte dei tutorial salta, e confonde un sacco di persone. L’escape e JSON.stringify sono due viste della stessa operazione, non due operazioni diverse.
JSON.stringify(value) serializza qualsiasi valore JavaScript nella sua rappresentazione testuale JSON. Quando quel valore è una stringa, serializzarla significa racchiuderla tra virgolette doppie e fare l’escape dei caratteri speciali al suo interno. Questo è esattamente l’escape JSON. Così JSON.stringify("a\tb") restituisce la stringa di sette caratteri "a\tb", virgolette comprese.
La domanda pratica è se vuoi quelle virgolette esterne. Questo corrisponde direttamente all’opzione Racchiudi tra virgolette doppie dello strumento Escape JSON:
| Modalità | Output per l’input a"b | Quando usarla |
|---|---|---|
| Racchiudi attivo | "a\"b" | Una stringa JSON letterale completa, identica a JSON.stringify. Assegnala a una variabile o incollala dopo i due punti. |
| Racchiudi disattivo | a\"b | Solo il corpo con l’escape, senza virgolette intorno. Usalo quando digiti tu stesso le virgolette dentro un documento JSON. |
Quindi se hai cercato “json stringify” e sei finito qui, il modello mentale è semplice: fare stringify di una stringa = escape con racchiudi attivo. La forma senza virgolette è la stessa cosa con le virgolette esterne rimosse.
Come fare l’escape di una stringa per JSON nel codice
La regola d’oro: non costruire mai a mano una catena di chiamate replace(). Ogni linguaggio diffuso include un serializzatore JSON che gestisce correttamente virgolette, backslash, caratteri di controllo e Unicode. Usalo.
JavaScript
const text = 'She said "hi"\nthen left.';
const escaped = JSON.stringify(text);
console.log(escaped);
// "She said \"hi\"\nthen left."
JSON.stringify su una stringa ti dà la stringa letterale completa, tra virgolette. Vuoi solo il corpo? Taglia il primo e l’ultimo carattere: 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 ha per default ensure_ascii=True, che fa l’escape di ogni carattere non-ASCII in \uXXXX, lo stesso comportamento della modalità ASCII-safe dello strumento. Passa ensure_ascii=False per mantenere l’UTF-8 grezzo.
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 fa l’escape sia dei caratteri non-ASCII sia delle barre per default. Aggiungi JSON_UNESCAPED_UNICODE per mantenere leggibili gli accenti e JSON_UNESCAPED_SLASHES per lasciare in pace /.
Go e Java
In Go, json.Marshal(text) restituisce i byte con l’escape e tra virgolette:
b, _ := json.Marshal(`a "quoted" line`)
// b == `"a \"quoted\" line"`
In Java, objectMapper.writeValueAsString(text) di Jackson o JSONObject.quote(text) di org.json producono la stessa stringa letterale tra virgolette. Qualunque sia il linguaggio, appoggiati alla libreria: conosce già ogni caso limite che dimenticheresti.
Annidare JSON dentro JSON (JSON-in-JSON)
Questo è di gran lunga il motivo più comune per cui si fa l’escape di JSON a mano. Un envelope di webhook, un record di una coda di messaggi o un log di audit spesso memorizza un intero corpo di richiesta come campo stringa. Per farlo, il JSON interno deve prima subire l’escape.
Guarda un piccolo oggetto attraversare due livelli di codifica:
1. Inner object: {"a":1}
2. Escaped as a string: "{\"a\":1}"
3. Placed in envelope: {"payload": "{\"a\":1}"}
Ogni " nell’oggetto interno è diventato \" e il tutto è stato racchiuso in una coppia esterna di virgolette. Il risultato è un singolo valore stringa valido che puoi assegnare a payload.
Il problema con un annidamento più profondo è che i backslash si moltiplicano. Fare l’escape di una stringa già con l’escape fa l’escape anche dei suoi backslash, quindi ogni livello li raddoppia all’incirca: una virgoletta interna che era \" diventa \\\" un livello più fuori e \\\\\" un altro livello ancora. Un JSON-in-JSON a tre livelli è davvero difficile da leggere, ed è qui che uno strumento aiuta. Per andare nella direzione opposta ed estrarre l’oggetto interno dalla stringa, fallo passare nel nostro strumento Unescape JSON.
Unicode ed escape \uXXXX
Per default, JSON va d’accordo con l’UTF-8 grezzo. Una é resta una é, un 日 resta un 日 e il documento è più leggibile così. Non devi fare l’escape di nessun carattere Unicode stampabile.
Allora quando converrebbe l’output ASCII-safe \uXXXX? Solo quando di un sistema a valle non ci si può fidare con l’UTF-8: vecchi gateway SOAP o XML, certe pipeline di logging, header email o file sorgente che devono restare puro ASCII. In modalità ASCII-safe, ogni carattere sopra U+007F diventa un escape \uXXXX: café si trasforma in caf\u00e9. È più rumoroso ma ASCII byte per byte, e si decodifica nuovamente nell’originale in qualsiasi parser conforme.
C’è una sottigliezza. \uXXXX codifica una singola unità di codice UTF-16 a 16 bit, ma i caratteri fuori dal Basic Multilingual Plane (emoji, scritture rare) richiedono 21 bit. JSON li gestisce con una coppia surrogata: due escape \uXXXX uno dopo l’altro. Una faccina sorridente 😀 (U+1F600) diventa \ud83d\ude00. La maggior parte dei serializzatori lo fa al posto tuo; il pericolo è un escaper scritto a mano che emette un surrogato isolato e spaiato.
Se le coppie surrogate e i code point sono territorio nuovo, la Guida UTF-8 vs UTF-16 vs Unicode spiega esattamente come un singolo carattere si mappa su byte e unità di codice. È il contesto mancante dietro il motivo per cui una emoji richiede due escape.
Unescape: rileggere il JSON con l’escape
L’escape ha il suo inverso. Per riportare "a\tb" al testo reale a due righe o con la tabulazione, lo analizzi: JSON.parse(str) in JavaScript, json.loads(str) in Python. Il parser percorre ogni sequenza di escape e ricostruisce i caratteri originali, coppie surrogate comprese.
Quando l’unescape fallisce, l’errore è quasi sempre “invalid escape sequence” e ha alcune cause tipiche:
- Un backslash isolato prima di un carattere che JSON non riconosce come escape, come
\q. - Un escape inventato come
\x41: JSON non ha l’escape esadecimale\x, usa solo\u. - Un escape
\utroncato con meno di quattro cifre esadecimali, come\u00. - Una virgoletta doppia vagante o non bilanciata che rompe il confine della stringa.
Verifica che ogni backslash apra uno degli escape validi (\n \r \t \b \f \" \\ \/ \uXXXX) e che le virgolette siano in coppia. Per le stringhe con l’escape copiate dal mezzo di una riga di log, dove le virgolette esterne sono rimaste indietro, il nostro strumento Unescape JSON accetta il corpo con o senza virgolette intorno e lo decodifica in entrambi i casi.
Errori comuni nell’escape JSON
La maggior parte dei payload rotti si riconduce a uno di questi sei errori.
1. Doppio escape. Fare l’escape di un testo già con l’escape trasforma \n in \\n e \" in \\\", così il consumatore legge un letterale backslash-n invece di un a capo. Di solito succede quando un servizio a monte ha già fatto l’escape JSON del valore e tu lo fai di nuovo. Fai prima l’unescape per controllare lo stato attuale, poi fai l’escape esattamente una volta.
2. Dimenticare le virgolette esterne. Con racchiudi disattivo ottieni solo il corpo con l’escape, non una stringa completa. Incollare hello \"world\" dove ci si aspetta un valore JSON è invalido perché mancano le virgolette intorno. O tieni racchiudi attivo oppure digiti tu le virgolette.
3. Escape eccessivo del non-ASCII. Attivare la modalità ASCII-safe quando il consumatore gestisce bene l’UTF-8 gonfia solo l’output. café diventa caf\u00e9 senza motivo: più difficile da leggere, più grande sulla rete, beneficio zero. Lascialo disattivo a meno che un sistema legacy specifico non richieda puro ASCII.
4. Fare l’escape della barra per riflesso. L’escape di / conta in un solo posto: il JSON inserito dentro un tag HTML <script>, dove la sottostringa </script> chiuderebbe il tag in anticipo a prescindere dal contesto JSON. Fare l’escape di / in \/ la neutralizza. Fuori da quel singolo caso, fare l’escape delle barre è solo disordine: lascialo disattivo per i corpi REST, i file di configurazione e i payload di messaggi.
5. Catene di replace scritte a mano. Una pipeline manuale replace('"', '\\"') dimentica quasi sempre qualcosa: un carattere di controllo, un backspace, una coppia surrogata. Usa il serializzatore del linguaggio, che copre l’intera specifica.
6. Fare l’escape ma mai l’unescape (o l’unescape due volte). Un round-trip deve bilanciarsi. Fai l’escape una volta in ingresso, l’unescape una volta in uscita. Fai l’unescape due volte e rovini i backslash reali che facevano parte dei dati.
Un’ultima distinzione che vale la pena fissare: l’escape JSON non è la codifica URL o percent-encoding. Risolvono problemi diversi per trasporti diversi, e mescolarli (fare il percent-encoding di un valore e poi l’escape JSON del risultato, o viceversa) produce un pasticcio che nessun parser riesce a leggere in modo pulito. La Guida alla codifica e decodifica URL spiega quando il percent-encoding è lo strumento giusto e in cosa differisce da ciò che fa JSON.
Domande frequenti
Cosa significa fare l’escape di una stringa in JSON?
Significa sostituire i caratteri che portano un significato strutturale per JSON (le virgolette doppie, il backslash e i caratteri di controllo come a capo e tabulazione) con sequenze di escape sicure come \", \\ e \n. Il risultato può essere inserito come stringa letterale dentro un documento JSON senza rompere l’analisi.
Quali caratteri devono ricevere l’escape in JSON?
Virgolette doppie, backslash, a capo, ritorno a capo, tabulazione, backspace e avanzamento modulo hanno ciascuno un escape dedicato, e ogni altro carattere di controllo sotto U+0020 diventa \uXXXX. I caratteri stampabili e l’UTF-8 multi-byte non richiedono escape; la barra è facoltativa e conta solo dentro i tag HTML <script>.
L’escape JSON è la stessa cosa di JSON.stringify?
Per lo più sono due viste di un’unica operazione. JSON.stringify applicato a una stringa la racchiude tra virgolette doppie e fa l’escape dei caratteri speciali al suo interno, ed è proprio questo l’escape JSON. Racchiudi attivo equivale alla forma tra virgolette (identica a JSON.stringify); racchiudi disattivo ti dà solo il corpo con l’escape, senza le virgolette intorno.
Come faccio l’escape di una stringa per JSON in JavaScript o Python?
In JavaScript usa JSON.stringify(str); in Python usa json.dumps(str). Affidati sempre alla funzione integrata invece che a una catena replace scritta a mano: le funzioni integrate gestiscono correttamente Unicode, caratteri di controllo e ogni caso limite che altrimenti ti sfuggirebbe.
Perché il mio JSON si rompe con backslash in più?
La causa abituale è il doppio escape: fare l’escape di un testo già con l’escape, così \n diventa \\n e il consumatore legge un letterale backslash-n invece di un a capo. Fai prima l’unescape del valore per controllarne lo stato reale, poi fai l’escape esattamente una volta.
Devo fare l’escape delle barre o dell’Unicode in JSON?
Nessuno dei due è obbligatorio. La / è un carattere normale e richiede l’escape solo quando inserisci JSON dentro un tag HTML <script>, per impedire alla sequenza </script> di chiuderlo in anticipo. L’Unicode resta UTF-8 grezzo per default; usa \uXXXX solo quando un sistema a valle non riesce a gestire l’UTF-8.