Comment échapper à une chaîne JSON contenant des caractères de nouvelle ligne à l'aide de JavaScript?

166

Je dois former une chaîne JSON dans laquelle une valeur a un nouveau caractère de ligne. Cela doit être échappé puis publié à l'aide de l'appel AJAX. Quelqu'un peut-il suggérer un moyen d'échapper à la chaîne avec JavaScript. Je n'utilise pas jQuery.

Srikant
la source
1
J'ai essayé d'échapper au caractère de nouvelle ligne \ n à \\ n. Cela fonctionne bien. Mais je recherche une bibliothèque JS qui peut le faire pour tous les caractères d'échappement.
Srikant
1
Pourquoi avez-vous besoin d'échapper aux nouvelles lignes dans le JSON? Comment ces valeurs sont-elles décodées lorsqu'elles sont utilisées, car la solution appropriée consiste à utiliser la fonction d'encodage associée.
zzzzBov
J'ai passé 6 heures à essayer toutes sortes de choses avec des tonnes de variations pour découvrir qu'une petite barre oblique supplémentaire ferait tout fonctionner comme par magie, les choses que je pensais difficiles ont pris environ 5 minutes ... la chose que je pensais avoir été donnée est devenue impossible. .omg
Muhammad Umer
1
Lorsque vous utilisez des appels Ajax avec sauvegarde php-db côté serveur, utilisez simplement la fonction php addlashes () pour le convertir. Avec cette solution, vous n'avez qu'un seul endroit pour convertir et son plus propre que les lignes javascript-replace.
Marcel Ennix

Réponses:

135

Prenez votre JSON et .stringify()ça. Utilisez ensuite la .replace()méthode et remplacez toutes les occurrences de \npar \\n.

ÉDITER:

Pour autant que je sache, il n'existe pas de bibliothèques JS bien connues pour échapper à tous les caractères spéciaux d'une chaîne. Mais vous pouvez chaîner la .replace()méthode et remplacer tous les caractères spéciaux comme ceci:

var myJSONString = JSON.stringify(myJSON);
var myEscapedJSONString = myJSONString.replace(/\\n/g, "\\n")
                                      .replace(/\\'/g, "\\'")
                                      .replace(/\\"/g, '\\"')
                                      .replace(/\\&/g, "\\&")
                                      .replace(/\\r/g, "\\r")
                                      .replace(/\\t/g, "\\t")
                                      .replace(/\\b/g, "\\b")
                                      .replace(/\\f/g, "\\f");
// myEscapedJSONString is now ready to be POST'ed to the server. 

Mais c'est assez méchant, n'est-ce pas? Entrez la beauté des fonctions, en ce qu'elles vous permettent de diviser le code en morceaux et de garder le flux principal de votre script propre et exempt de 8 .replace()appels en chaîne . Mettons donc cette fonctionnalité dans une fonction appelée escapeSpecialChars(),. Allons allez - y et le joindre à la prototype chainde l' Stringobjet, afin que nous puissions appeler escapeSpecialChars()directement sur des objets String.

Ainsi:

String.prototype.escapeSpecialChars = function() {
    return this.replace(/\\n/g, "\\n")
               .replace(/\\'/g, "\\'")
               .replace(/\\"/g, '\\"')
               .replace(/\\&/g, "\\&")
               .replace(/\\r/g, "\\r")
               .replace(/\\t/g, "\\t")
               .replace(/\\b/g, "\\b")
               .replace(/\\f/g, "\\f");
};

Une fois que nous avons défini cette fonction, le corps principal de notre code est aussi simple que ceci:

var myJSONString = JSON.stringify(myJSON);
var myEscapedJSONString = myJSONString.escapeSpecialChars();
// myEscapedJSONString is now ready to be POST'ed to the server
Alex
la source
3
Merci Alex. Je dois faire ça pour tous les personnages d'échappement, non? Existe-t-il une bibliothèque JS pour ce faire?
Srikant
2
C'est la fonction exacte qui a résolu mon problème String.prototype.escapeSpecialChars = function () {return this.replace (/ \\ / g, "\\\\"). remplacer (/ \ n / g, "\\ n"). remplacez (/ \ r / g, "\\ r"). remplacer (/ \ t / g, "\\ t"). remplacer (/ \ f / g, "\\ f"). remplacer (/ "/ g," \\\ ""). remplacer (/ '/ g, "\\\'"). remplacer (/ \ & / g, "\\ &"); }
Srikant
10
Comme indiqué dans la réponse de user667073, il y a quelques erreurs dans cette solution. Voir json.org - & et ' ne doit pas être échappé.
Alexander Klimetschek
5
J'ai dû voter contre cela car les expressions régulières semblent être fausses. J'ai essayé de l'utiliser, mais j'ai dû corriger les expressions régulières en supprimant l'une des barres obliques, par exemple: / \\ n / g devrait être / \ n / g. Voir «Caractères non imprimables» sur ce lien pour plus de détails - RegExp Info
b01
1
qu'en est-il de \ lui-même? devrait-il également être échappé?
arash moeen
65

Selon user667073 suggéré, sauf réorganiser d'abord le remplacement de la barre oblique inverse et réparer le remplacement du devis

escape = function (str) {
  return str
    .replace(/[\\]/g, '\\\\')
    .replace(/[\"]/g, '\\\"')
    .replace(/[\/]/g, '\\/')
    .replace(/[\b]/g, '\\b')
    .replace(/[\f]/g, '\\f')
    .replace(/[\n]/g, '\\n')
    .replace(/[\r]/g, '\\r')
    .replace(/[\t]/g, '\\t');
};
Ryan
la source
3
Vous n'êtes pas obligé de faire tout cela. Seulement barre oblique inverse, nouvelle ligne, saut de ligne et les deux guillemets. Et il manque: guillemet simple, Line separator \u2028et Paragraph separator \u2029. Ref: es5.github.io/#x7.3
Ariel
1
Bien, mais pourquoi les crochets sont-ils nécessaires et non: escape = function (str) {return str .replace (/ \\ / g, '\\\\') .replace (/ \ "/ g, '\\\ "') .replace (/ \ // g,' \\ / ') .replace (/ \ b / g,' \\ b ') .replace (/ \ f / g,' \\ f ') .replace (/ \ n / g, '\\ n') .replace (/ \ r / g, '\\ r') .replace (/ \ t / g, '\\ t'); };
Johann Echavarria
3
parfait. la réponse acceptée (au-dessus de celle-ci) ne fonctionne tout simplement pas. en utilisant nodeJS.
Yossi Shasho le
Uncaught SyntaxError: Unexpected token \ in JSON at position 2
J'obtiens
32

Comme vous, j'ai examiné plusieurs commentaires et posté pour remplacer les caractères d'échappement spéciaux dans mon JSON qui contient un objet html à l'intérieur.

Mon objectif est de supprimer les caractères spéciaux dans l'objet JSON et également de rendre le html qui se trouve à l'intérieur de l'objet json.

Voici ce que j'ai fait et j'espère que c'est très simple à utiliser.

J'ai d'abord fait JSON.stringify mon objet json et JSON.parse le résultat.

Par exemple:

JSON.parse(JSON.stringify(jsonObject));

Et cela résout mon problème et fait en utilisant Pure Javascript.

Balasubramani M
la source
4
C'est définitivement la voie à suivre
Oz Lodriguez
1
C'est définitivement la voie à suivre!
MartianE
1
Cela va certainement casser sur des objets complexes et volumineux avec une stackoverflowerreur
AaA
1
essayez JSON.parse(JSON.stringify($("body")))dans un fichier html avec corps et quelques tableaux. $ ("body") est un objet javascript mais stringify échouera à l'analyse.
AaA
Je vais vérifier votre requête et revenir en arrière.
Balasubramani M
24

J'ai peur de dire que la réponse d'Alex est plutôt incorrecte, pour le dire légèrement:

  • Certains personnages qu'Alex tente de s'échapper ne sont pas du tout obligés d'être échappés (comme & et ');
  • \ b n'est pas du tout le caractère de retour arrière mais plutôt une correspondance de limite de mot
  • Les caractères devant être échappés ne sont pas gérés.

Cette fonction

escape = function (str) {
    // TODO: escape %x75 4HEXDIG ?? chars
    return str
      .replace(/[\"]/g, '\\"')
      .replace(/[\\]/g, '\\\\')
      .replace(/[\/]/g, '\\/')
      .replace(/[\b]/g, '\\b')
      .replace(/[\f]/g, '\\f')
      .replace(/[\n]/g, '\\n')
      .replace(/[\r]/g, '\\r')
      .replace(/[\t]/g, '\\t')
    ; };

semble être une meilleure approximation.

whaefelinger
la source
5
en fait, vous devez changer l'ordre pour remplacer les barres obliques inverses avant les guillemets, sinon vous vous retrouverez avec \\\\ ". La ligne de guillemet devrait également être .replace (/ [\"] / g, '\\\ "')
Ryan
10

Une petite mise à jour pour les guillemets simples

function escape (key, val) {
    if (typeof(val)!="string") return val;
    return val      
        .replace(/[\\]/g, '\\\\')
        .replace(/[\/]/g, '\\/')
        .replace(/[\b]/g, '\\b')
        .replace(/[\f]/g, '\\f')
        .replace(/[\n]/g, '\\n')
        .replace(/[\r]/g, '\\r')
        .replace(/[\t]/g, '\\t')
        .replace(/[\"]/g, '\\"')
        .replace(/\\'/g, "\\'"); 
}

var myJSONString = JSON.stringify(myJSON,escape);
Akash Dhawale
la source
7

ceci est un ancien message. mais cela peut toujours être utile pour ceux qui utilisent angular.fromJson et JSON.stringify. escape () est obsolète. utilisez plutôt ceci,

var uri_enc = encodeURIComponent(uri); //before you post the contents
var uri_dec = decodeURIComponent(uri_enc); //before you display/use the contents.

réf http://www.w3schools.com/jsref/jsref_decodeuricomponent.asp

Sam
la source
stringify fait déjà tout ce qui s'échappe pour vous - je suis curieux de savoir pourquoi ne pas simplement l'utiliser? git.io/vglq7
Ben Davis
5

Il existe également un deuxième paramètre sur JSON.stringify. Donc, une solution plus élégante serait:

function escape (key, val) {
    if (typeof(val)!="string") return val;
    return val
      .replace(/[\"]/g, '\\"')
      .replace(/[\\]/g, '\\\\')
      .replace(/[\/]/g, '\\/')
      .replace(/[\b]/g, '\\b')
      .replace(/[\f]/g, '\\f')
      .replace(/[\n]/g, '\\n')
      .replace(/[\r]/g, '\\r')
      .replace(/[\t]/g, '\\t')
    ; 
}

var myJSONString = JSON.stringify(myJSON,escape);
Krunoslav Djakovic
la source
5

C'est une vieille question mais la solution ne fonctionnait pas bien pour moi car elle ne résolvait pas tous les cas. J'ai enfin trouvé une réponse qui a fait le travail ici

Je publierai ma solution combinée à la fois en utilisant escape et encoder le composant uri:

// implement JSON stringify serialization
JSON.stringify = JSON.stringify || function (obj) {
    var t = typeof (obj);
    if (t != "object" || obj === null) {
        // simple data type
        if (t == "string") obj = '"'+obj+'"';
        return String(obj);
    }
    else {
        // recurse array or object
        var n, v, json = [], arr = (obj && obj.constructor == Array);
        for (n in obj) {
            v = obj[n]; t = typeof(v);
            if (t == "string") v = '"'+v+'"';
            else if (t == "object" && v !== null) v = JSON.stringify(v);
            json.push((arr ? "" : '"' + n + '":') + String(v));
        }
        var rawString = (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
       return rawString;
    }
};
function escape (key, val) {
    if (typeof(val)!="string") return val;

    var replaced = encodeURIComponent(val);
    return replaced;
}

JSON.stringifyEscaped = function(obj){
    return JSON.stringify(obj,escape);
}
Mitzi
la source
Peut-être supprimer les guillemets doubles autour de la chaîne par la suite aussi? escape = (string) -> JSON.stringify(string)[1...-1]
Radek
3

Il vaut mieux utiliser JSON.parse(yourUnescapedJson);

Mohit Vachhani
la source
3

Utilisez json_encode () si votre langage de script côté serveur est PHP, json_encode()échappe la nouvelle ligne et d'autres jetons inattendus pour vous (si vous n'utilisez pas PHP, recherchez une fonction similaire pour votre langage de script)

puis utilisez $.parseJSON()dans votre JavaScript, c'est fait!

avngr
la source
Si vous passez des données de php à javascript en tant que chaîne JSON, vérifiez cette réponse - double échappement, m'a aidé à passer JSON.parse et à convertir la chaîne json en objet. <script> windows.data_from_php = <?php echo json_encode(json_encode($arrayOrObjToJs)); ?>; var phpData = JSON.parse(windows.data_from_php); </script> php JSON.parse double encodage
Vladimir Vukanac
2

J'ai eu la même situation dans l'un de mes appels Ajax, où JSONune erreur était générée en raison de la nouvelle ligne dans le champ Textarea. La solution donnée ici n'a pas fonctionné pour moi. J'ai donc utilisé la .escapefonction de Javascript et cela a bien fonctionné. Ensuite, pour récupérer la valeur de JSON, je viens de ne pas utiliser .unescape.

Anubhav Trivedi
la source
En utilisant les appels Ajax, je préfère utiliser php-function newStr = addedlashes (str), puis enregistrer dans db. Je n'ai donc pas besoin de convertir du côté javascript (client). Avec cette solution, vous n'avez besoin que d'un seul endroit pour convertir les barres obliques. Je suis très content de cette solution.
Marcel Ennix
2

J'ai utilisé le jQuery.serialize () intégré pour extraire la valeur d'une zone de texte pour encoder l'URL de l'entrée. La partie pro est que vous n'avez pas à rechercher de remplacer chaque caractère spécial par vous-même et je garde également les nouvelles lignes et les échappements html. Pour que la sérialisation fonctionne, il semble que le champ d'entrée doit avoir un attribut de nom et il ajoute également le même attribut à la chaîne échappée qui doit être remplacée. Ce n'est peut-être pas ce que vous recherchez, mais cela fonctionne pour moi.

var myinputfield = jQuery("#myinputfield"); 
var text = myinputfield.serialize();
text = text.replace(myinputfield.attr('name') + '=','');
Janspeed
la source
1

Lors de l'utilisation de toute forme d'Ajax, une documentation détaillée sur le format des réponses reçues du serveur CGI semble manquer sur le Web. Certaines entrées ici soulignent que les retours à la ligne dans le texte retourné ou les données json doivent être échappés pour éviter les boucles infinies (se bloque) dans la conversion JSON (éventuellement créé en lançant une exception non interceptée), que ce soit fait automatiquement par jQuery ou manuellement à l'aide du système Javascript ou de la bibliothèque d'analyse JSON appels.

Dans chaque cas où les programmeurs publient ce problème, des solutions inadéquates sont présentées (le plus souvent en remplaçant \ n par \\ n côté envoi) et le problème est abandonné. Leur inadéquation est révélée lors de la transmission de valeurs de chaîne qui intègrent accidentellement des séquences d'échappement de contrôle, telles que les chemins d'accès Windows. Un exemple est "C: \ Chris \ Roberts.php", qui contient les caractères de contrôle ^ c et ^ r, ce qui peut provoquer la conversion JSON de la chaîne {"file": "C: \ Chris \ Roberts.php"} en boucle pour toujours. Une façon de générer de telles valeurs est de tenter délibérément de transmettre des messages d'avertissement et d'erreur PHP du serveur au client, une idée raisonnable.

Par définition, Ajax utilise des connexions HTTP dans les coulisses. Ces connexions transmettent des données à l'aide de GET et POST, qui nécessitent tous deux le codage des données envoyées pour éviter une syntaxe incorrecte, y compris des caractères de contrôle.

Cela donne suffisamment d'indices pour construire ce qui semble être une solution (il faut plus de tests): utiliser rawurlencode du côté PHP (envoi) pour encoder les données, et unscape du côté Javascript (réception) pour décoder les données. Dans certains cas, vous les appliquerez à des chaînes de texte entières, dans d'autres cas, vous les appliquerez uniquement aux valeurs dans JSON.

Si cette idée s'avère correcte, des exemples simples peuvent être construits pour aider les programmeurs à tous les niveaux à résoudre ce problème une fois pour toutes.

David Spector
la source
0

On dirait que c'est vraiment un article ancien :-) Mais les gars, la meilleure solution de contournement que j'ai pour cela, être à 100% que cela fonctionne sans code compliqué, est d'utiliser les deux fonctions d'encodage / décodage en base64. Ce sont atob () et btoa (). De loin le moyen le plus simple et le meilleur, pas besoin de s'inquiéter si vous avez manqué des caractères à échapper.

George

Giorgoc
la source
Depuis que j'ai trouvé la même solution. Je me demande si quelqu'un pourrait clarifier cette solution et s'il y a des mises en garde cachées. Merci.
mahish
0

Si vos Googles continuent de vous atterrir ici et que votre API génère des erreurs à moins que vos guillemets JSON ne soient échappés ( "{\"foo\": true}"), tout ce que vous avez à faire est de stringify deux fois, par exempleJSON.stringify(JSON.stringify(bar))

Avolition
la source
-1

Utilisez encodeURIComponent () pour encoder la chaîne.

Par exemple. var myEscapedJSONString = encodeURIComponent (JSON.stringify (myJSON));

Vous n'avez pas besoin de le décoder car le serveur Web fait automatiquement de même.

Sanju Kaniyamattam
la source
-8

N'utilisez jamais d'expressions régulières (je veux dire comme jamais du tout). Le meilleur moyen efficace:

String.prototype.escapeJSON = function() {
    var result = "";
    for (var i = 0; i < this.length; i++)
    {
        var ch = this[i];
        switch (ch)
        {
            case "\\": ch = "\\\\"; break;
            case "\'": ch = "\\'"; break;
            case "\"": ch = '\\"'; break;
            case "\&": ch = "\\&"; break;
            case "\t": ch = "\\t"; break;
            case "\n": ch = "\\n"; break;
            case "\r": ch = "\\r"; break;
            case "\b": ch = "\\b"; break;
            case "\f": ch = "\\f"; break;
            case "\v": ch = "\\v"; break;
            default: break;
        }

        result += ch;
    }

    return result;
};
Alek Depler
la source
Vous ne pouvez pas dire "N'utilisez jamais d'expressions régulières (je veux dire comme jamais du tout)". Chaque outil sert son objectif.
zstate le
Votre réponse est valable, vous venez de l'exprimer d'une manière très opiniâtre, ce qui pourrait créer de la confusion, en particulier pour les juniors.
zstate le
Les expressions régulières @oncode sont incroyablement inutiles, peu importe comment et quand les utiliser. Cela ne conduit qu'à un comportement indéfini et à une perte de temps CPU.
Alek Depler le