JSON-strings escapen: tekens, stringify en valkuilen
Een JSON-string escapen betekent dat je willekeurige tekst omzet naar een string die veilig binnen een JSON-document kan staan als string-literal. Een handvol tekens, zoals het dubbele aanhalingsteken, de backslash en stuurtekens als newline en tab, dragen structurele betekenis of zijn verboden binnen een JSON-string. Elk zo’n teken wordt vervangen door een veilige escape-reeks zoals \", \\ of \n. Doe je dit verkeerd, dan stopt je payload met parsen.
Je loopt hier voortdurend tegenaan: een JSON-object als string-veld in een ander object nesten, een meerregelig codefragment in een configuratiewaarde plakken, of met de hand een REST-request-body voor curl bouwen. Deze gids behandelt precies welke tekens je moet escapen, ruimt de verwarring tussen escapen en JSON.stringify op, loopt door JSON-in-JSON-nesting en Unicode-escapes, en somt de valkuilen op die stilletjes je payloads breken. Wil je gewoon meteen iets escapen, dan doet onze tool JSON escapen het in je browser. Lees verder voor waarom het werkt zoals het werkt.
Wat is JSON-string-escaping?
JSON-string-escaping zet een ruwe string om naar een vorm die veilig binnen een JSON-document kan worden ingebed. JSON reserveert een kleine set tekens met structurele betekenis: het dubbele aanhalingsteken " begrenst een string en de backslash \ start een escape-reeks. Stuurtekens onder U+0020, zoals newlines, tabs en carriage returns, mogen ook niet letterlijk binnen een JSON-string verschijnen. Escapen vervangt elk van deze tekens door een veilige reeks, zodat de resulterende string overal netjes parst.
Wanneer heb je het echt nodig? Een paar situaties komen steeds terug:
- JSON-in-JSON: een webhook-envelop, een Kafka-bericht of een audit-log bewaart een request-body als string-veld, dus de binnenste JSON moet worden geëscapet voordat hij kan worden toegekend.
- Handgeschreven configuratie: een meerregelig shell-script, SQL-query of codefragment in één JSON-waarde zetten betekent dat je elke newline omzet naar
\n. - REST-request-bodies: een JSON-body met de hand bouwen voor
curlof een HTTP-client, waar aanhalingstekens en newlines de shell en de verbinding moeten overleven. - Log-veilige codering: door gebruikers aangeleverde inhoud in een gestructureerde logregel schrijven zonder dat een ingevoegd aanhalingsteken of newline de structuur verstoort.
Nog even iets over de volgorde van bewerkingen. Begin je met rommelige of niet-vertrouwde JSON, valideer die dan eerst zodat je iets welgevormds escapet. Plak hem in de JSON Formatter om hem netjes weer te geven en te controleren, en escape daarna het schone resultaat. Rommel escapen levert alleen geëscapete rommel op.
Welke tekens moet je escapen in JSON
De JSON-specificatie definieert een precieze, korte lijst. Zeven tekens hebben een eigen escape van twee tekens, en al het andere onder U+0020 valt terug op een \uXXXX-Unicode-escape. Hier is de complete set JSON-escape-tekens:
| Teken | Escapet naar | Toelichting |
|---|---|---|
" (U+0022) | \" | String-begrenzing |
\ (U+005C) | \\ | Begin van een escape (het json-escape-backslash-geval) |
| newline (U+000A) | \n | |
| carriage return (U+000D) | \r | |
| tab (U+0009) | \t | |
| backspace (U+0008) | \b | |
| form feed (U+000C) | \f | |
| overige stuurtekens < U+0020 | \uXXXX | bijv. U+0000 → \u0000 |
Wat niet geëscapet hoeft te worden is net zo belangrijk. De forward slash / is een volkomen normaal teken (hem escapen is optioneel en alleen nuttig in één smal geval dat hieronder aan bod komt). Enkele aanhalingstekens hoeven nooit geëscapet te worden, omdat JSON ze niet als begrenzing gebruikt. En elk afdrukbaar teken vanaf U+0020, inclusief alle multibyte-UTF-8-tekens zoals é, 日 of 😀, is gewoon geldig zoals het is.
Hier is het verschil concreet gemaakt. De ruwe invoer links, de geëscapete JSON-string-literal rechts:
Input:
She said "hello" then left.
Escaped:
"She said \"hello\"\tthen left."
De dubbele aanhalingstekens werden \" en de tab werd \t. Nu is de string veilig om in elke JSON-parser, logregel of request-body te zetten.
JSON escapen versus JSON stringify: wat is het verschil?
Dit is het punt dat de meeste tutorials overslaan, en het brengt veel mensen in de war. Escapen en JSON.stringify zijn niet twee verschillende bewerkingen, maar twee invalshoeken op dezelfde bewerking.
JSON.stringify(value) serialiseert elke JavaScript-waarde naar de JSON-tekstrepresentatie ervan. Wanneer die waarde toevallig een string is, betekent serialiseren dat je hem in dubbele aanhalingstekens zet en de speciale tekens erin escapet. Dat is precies JSON-escaping. Dus JSON.stringify("a\tb") geeft de string van zeven tekens "a\tb" terug, aanhalingstekens inbegrepen.
De praktische vraag is of je die buitenste aanhalingstekens wilt. Dat sluit rechtstreeks aan op de optie Wrap in double quotes in de tool JSON escapen:
| Modus | Uitvoer voor invoer a"b | Wanneer gebruik je het |
|---|---|---|
| Wrap aan | "a\"b" | Een complete JSON-string-literal, identiek aan JSON.stringify. Ken hem toe aan een variabele of plak hem achter een dubbele punt. |
| Wrap uit | a\"b | Alleen de geëscapete inhoud, zonder omringende aanhalingstekens. Gebruik dit wanneer je de aanhalingstekens zelf typt in een JSON-document. |
Dus als je op “json stringify” zocht en hier belandde, is het mentale model simpel: een string stringify-en = escapen met wrap aan. De vorm zonder aanhalingstekens is hetzelfde, met de buitenste aanhalingstekens eraf gepeld.
Zo escape je een string voor JSON in code
De gouden regel: knutsel nooit een keten van replace()-aanroepen in elkaar. Elke gangbare taal levert een JSON-serializer die aanhalingstekens, backslashes, stuurtekens en Unicode correct afhandelt. Grijp daarnaar.
JavaScript
const text = 'She said "hi"\nthen left.';
const escaped = JSON.stringify(text);
console.log(escaped);
// "She said \"hi\"\nthen left."
JSON.stringify op een string geeft je de complete literal met aanhalingstekens. Wil je alleen de inhoud? Knip het eerste en laatste teken eraf: 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 heeft standaard ensure_ascii=True, wat elk niet-ASCII-teken naar \uXXXX escapet, hetzelfde gedrag als de ASCII-veilige modus van de tool. Geef ensure_ascii=False mee om ruwe UTF-8 te behouden.
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 escapet standaard zowel niet-ASCII-tekens als forward slashes. Voeg JSON_UNESCAPED_UNICODE toe om accenten leesbaar te houden, en JSON_UNESCAPED_SLASHES om / met rust te laten.
Go en Java
In Go geeft json.Marshal(text) de geëscapete bytes met aanhalingstekens terug:
b, _ := json.Marshal(`a "quoted" line`)
// b == `"a \"quoted\" line"`
In Java leveren Jacksons objectMapper.writeValueAsString(text) of JSONObject.quote(text) van org.json dezelfde literal met aanhalingstekens op. Welke taal je ook gebruikt, leun op de bibliotheek. Die kent al elk randgeval dat jij zou vergeten.
JSON in JSON inbedden (JSON-in-JSON)
Dit is veruit de meest voorkomende reden waarom mensen JSON met de hand escapen. Een webhook-envelop, een record uit een message-queue of een audit-log bewaart vaak een hele request-body als string-veld. Daarvoor moet de binnenste JSON eerst worden geëscapet.
Kijk hoe een klein object door twee lagen codering reist:
1. Inner object: {"a":1}
2. Escaped as a string: "{\"a\":1}"
3. Placed in envelope: {"payload": "{\"a\":1}"}
Elke " in het binnenste object werd \", en het geheel kreeg één buitenste paar aanhalingstekens. Het resultaat is één geldige string-waarde die je aan payload kunt toekennen.
De adder onder het gras bij diepere nesting is dat backslashes zich vermenigvuldigen. Een al geëscapete string nog eens escapen escapet ook zijn backslashes, dus elke laag verdubbelt ze ongeveer: een binnenste aanhalingsteken dat \" was, wordt \\\" één niveau eruit, en \\\\\" weer een niveau verder. JSON-in-JSON van drie niveaus diep is werkelijk lastig te lezen, en daarom helpt een tool. Om de andere kant op te gaan en het binnenste object weer uit de string te halen, haal je hem door onze tool JSON unescapen.
Unicode en \uXXXX-escaping
Standaard is JSON tevreden met ruwe UTF-8. Een é blijft een é, een 日 blijft een 日, en het document is er leesbaarder door. Je hoeft geen enkel afdrukbaar Unicode-teken te escapen.
Wanneer zou je dan wel naar ASCII-veilige \uXXXX-uitvoer grijpen? Alleen wanneer een achterliggend systeem geen UTF-8 aankan: oude SOAP- of XML-gateways, bepaalde logging-pipelines, e-mailheaders, of bronbestanden die puur ASCII moeten blijven. In de ASCII-veilige modus wordt elk teken boven U+007F een \uXXXX-escape, dus café wordt caf\u00e9. Het is rommeliger maar byte voor byte ASCII, en het decodeert terug naar het origineel in elke conforme parser.
Er is één subtiliteit. \uXXXX codeert een enkele 16-bits UTF-16-code-unit, maar tekens buiten het Basic Multilingual Plane (emoji, zeldzame schriften) hebben 21 bits nodig. JSON handelt ze af met een surrogate pair: twee \uXXXX-escapes achter elkaar. Een grijnzend gezicht 😀 (U+1F600) wordt \ud83d\ude00. De meeste serializers doen dit voor je; het gevaar zit in een handgeschreven escaper die een losse, ongepaarde surrogate uitstoot.
Zijn surrogate pairs en codepunten nieuw terrein voor je, dan legt de UTF-8 vs UTF-16 vs Unicode encoding-gids precies uit hoe een enkel teken naar bytes en code-units afbeeldt. Dat is de ontbrekende context achter waarom één emoji twee escapes nodig heeft.
Unescapen: geëscapete JSON teruglezen
Escapen heeft een omgekeerde. Om "a\tb" terug te zetten naar de echte tekst met tab, parse je hem: JSON.parse(str) in JavaScript, json.loads(str) in Python. De parser loopt elke escape-reeks af en bouwt de oorspronkelijke tekens weer op, surrogate pairs inbegrepen.
Wanneer unescapen mislukt, is de fout bijna altijd “invalid escape sequence”, en die heeft een paar gebruikelijke oorzaken:
- Een losse backslash vóór een teken dat JSON niet als escape herkent, zoals
\q. - Een verzonnen escape zoals
\x41; JSON heeft geen\x-hex-escape en gebruikt alleen\u. - Een afgekapte
\u-escape met minder dan vier hexadecimale cijfers, zoals\u00. - Een verdwaald of niet-gebalanceerd dubbel aanhalingsteken dat de string-grens breekt.
Controleer of elke backslash een van de geldige escapes start (\n \r \t \b \f \" \\ \/ \uXXXX) en of de aanhalingstekens gepaard zijn. Voor geëscapete strings die je uit het midden van een logregel hebt gekopieerd, waar de buitenste aanhalingstekens zijn achtergebleven, accepteert onze tool JSON unescapen de inhoud met of zonder omringende aanhalingstekens en decodeert hem hoe dan ook.
Veelvoorkomende valkuilen bij JSON-escaping
De meeste kapotte payloads zijn terug te voeren op een van deze zes fouten.
1. Dubbel escapen. Tekst escapen die al geëscapet was, verandert \n in \\n en \" in \\\", zodat de consument een letterlijke backslash-n leest in plaats van een newline. Dit gebeurt meestal wanneer een upstream-service de waarde al JSON-geëscapet heeft en jij hem nog eens escapet. Unescape eerst om de huidige stand te controleren, en escape daarna precies één keer.
2. De buitenste aanhalingstekens vergeten. Met wrap uit krijg je alleen de geëscapete inhoud, geen complete string. hello \"world\" rechtstreeks plakken waar een JSON-waarde wordt verwacht is ongeldig, omdat de omringende aanhalingstekens ontbreken. Houd óf wrap aan, óf typ de aanhalingstekens zelf.
3. Niet-ASCII over-escapen. De ASCII-veilige modus aanzetten terwijl de consument prima met UTF-8 overweg kan, blaast de uitvoer alleen maar op. café wordt caf\u00e9 zonder reden: slechter leesbaar, groter over de verbinding, nul voordeel. Laat het uit, tenzij een specifiek verouderd systeem puur ASCII vereist.
4. De forward slash uit reflex escapen. De /-escape doet er op precies één plek toe: JSON dat is ingebed in een HTML-<script>-tag, waar de tekenreeks </script> de tag voortijdig zou sluiten, los van de JSON-context. / escapen naar \/ schakelt dat uit. Buiten dat ene geval is slashes escapen pure rommel; laat het uit voor REST-bodies, configuratiebestanden en bericht-payloads.
5. Zelfgemaakte replace-ketens. Een handmatige replace('"', '\\"')-pijplijn vergeet bijna altijd iets: een stuurteken, een backspace, een surrogate pair. Gebruik de serializer van de taal, die de hele specificatie dekt.
6. Wel escapen maar nooit unescapen (of twee keer unescapen). Een rondreis moet kloppen. Escape één keer op de heenweg, unescape één keer op de terugweg. Unescape twee keer en je verminkt echte backslashes die deel uitmaakten van de data.
Nog één onderscheid dat het waard is om vast te pinnen: JSON-escaping is niet hetzelfde als URL- of percent-encodering. Ze lossen verschillende problemen op voor verschillende transporten, en ze door elkaar gebruiken (een waarde percent-encoderen en het resultaat daarna JSON-escapen, of andersom) levert een knoeiboel op die geen van beide parsers schoon kan lezen. De URL-encoderen en -decoderen gids behandelt wanneer percent-encodering het juiste gereedschap is en hoe het verschilt van wat JSON doet.
Veelgestelde vragen
Wat betekent het om een string in JSON te escapen?
Het betekent dat je de tekens met structurele betekenis voor JSON, zoals het dubbele aanhalingsteken, de backslash en stuurtekens als newline en tab, vervangt door veilige escape-reeksen zoals \", \\ en \n. Het resultaat kan als string-literal binnen een JSON-document worden ingebed zonder de parse te breken.
Welke tekens moeten in JSON geëscapet worden?
Het dubbele aanhalingsteken, de backslash, newline, carriage return, tab, backspace en form feed krijgen elk een eigen escape, en elk ander stuurteken onder U+0020 wordt \uXXXX. Afdrukbare tekens en multibyte-UTF-8 hoeven niet geëscapet te worden; de forward slash is optioneel en doet er alleen toe binnen HTML-<script>-tags.
Is JSON escapen hetzelfde als JSON.stringify?
Grotendeels twee invalshoeken op één bewerking. JSON.stringify toegepast op een string zet hem in dubbele aanhalingstekens en escapet de speciale tekens erin, en dat is precies JSON-escaping. Wrap aan staat gelijk aan de vorm met aanhalingstekens (identiek aan JSON.stringify); wrap uit geeft je alleen de geëscapete inhoud zonder de omringende aanhalingstekens.
Hoe escape ik een string voor JSON in JavaScript of Python?
In JavaScript gebruik je JSON.stringify(str); in Python gebruik je json.dumps(str). Leun altijd op de ingebouwde functie in plaats van een zelfgeschreven replace-keten. Die verwerkt Unicode, stuurtekens en elk randgeval dat je anders zou missen correct.
Waarom breekt mijn JSON met extra backslashes?
De gebruikelijke oorzaak is dubbel escapen: tekst escapen die al geëscapet was, zodat \n \\n wordt en de consument een letterlijke backslash-n leest in plaats van een newline. Unescape de waarde eerst om de echte stand te controleren, en escape hem daarna precies één keer.
Moet ik forward slashes of Unicode in JSON escapen?
Geen van beide is verplicht. De / is een normaal teken en hoeft alleen geëscapet te worden wanneer je JSON inbedt in een HTML-<script>-tag, om te voorkomen dat de reeks </script> hem voortijdig sluit. Unicode blijft standaard ruwe UTF-8; gebruik \uXXXX alleen wanneer een achterliggend systeem geen UTF-8 aankan.