Wie gehe ich mit Zeilenumbrüchen in JSON um?

288

Ich habe JSON generiert und versuche, es in ein Objekt in JavaScript zu ziehen. Ich bekomme immer wieder Fehler. Folgendes habe ich:

var data = '{"count" : 1, "stack" : "sometext\n\n"}';
var dataObj = eval('('+data+')');

Dies gibt mir einen Fehler:

unterminated string literal

Mit JSON.parse(data)werden ähnliche Fehlermeldungen angezeigt: " Unexpected token ↵" in Chrome und " unterminated string literal" in Firefox und IE.

Wenn ich das herausnehme, \nverschwindet sometextder Fehler in beiden Fällen. Ich kann nicht herausfinden, warum das \nmacht evalund JSON.parsescheitert.

Eisbär
quelle
19
Versuchen Sie es mit einem echten JSON-Parser anstelle von eval.
Eric

Antworten:

367

Ich denke, das ist was du willst:

var data = '{"count" : 1, "stack" : "sometext\\n\\n"}';

(Sie müssen das "\" in Ihrer Zeichenfolge maskieren (in ein doppeltes "\" umwandeln), sonst wird es zu einer neuen Zeile in der JSON-Quelle, nicht in den JSON-Daten.)

BlaM
quelle
100
Dies ist natürlich richtig, aber ich möchte den Grund dafür hinzufügen: Die JSON-Spezifikation unter ietf.org/rfc/rfc4627.txt enthält diesen Satz in Abschnitt 2.5: "Alle Unicode-Zeichen können innerhalb der platziert werden Anführungszeichen mit Ausnahme der Zeichen, die maskiert werden müssen: Anführungszeichen, umgekehrter Solidus und die Steuerzeichen (U + 0000 bis U + 001F). " Da eine neue Zeile ein Steuerzeichen ist, muss sie maskiert werden.
Daniel Kullmann
1
Laut www.json.org akzeptiert JSON die Kontrollsequenz "\ n" in Strings - und wenn Sie JSON.parse (['"a \\ na"']) [1] .charCodeAt () versuchen; das zeigt 10 - das war "Linefeed", als ich das letzte Mal nachgesehen habe. Übrigens: Hör auf zu schreien!
BlaM
+ 1. Ich hatte Probleme beim Verständnis der JSON-Codierung, aber "wird eine neue Zeile in der JSON-Quelle, nicht die JSON-Daten" machte es mir klar.
Amucunguzi
44

Sie benötigen eine Funktion, die ersetzt wird \n, \\nfalls dataes sich nicht um ein Zeichenfolgenliteral handelt.

function jsonEscape(str)  {
    return str.replace(/\n/g, "\\\\n").replace(/\r/g, "\\\\r").replace(/\t/g, "\\\\t");
}

var data = '{"count" : 1, "stack" : "sometext\n\n"}';
var dataObj = JSON.parse(jsonEscape(data));

Ergebnis dataObjwird sein

Object {count: 1, stack: "sometext\n\n"}
manish_s
quelle
3
Sie müssen Ihren .replace("\\n", "\\\\n").replace(/\n/g, "\\\\n")
Fluchtzeichen
2
Warum musst du Fluchtcharakteren entkommen? Ich meine, so etwas .replace("\n", "\\n")sollte den Job gut machen !! Zum Beispiel var test = [{"description":"Some description about the product. This can be multi-line text."}]; console.log(JSON.parse(test.replace(/\n/g, "\\n")));wird das Objekt perfekt in der Browserkonsole als[{"description":"Some description about the product.\nThis can be multi-line text."}]
Fr0zenFyr
Übrigens, im obigen Kommentar hat die ursprüngliche JSON-Zeichenfolge eine neue Zeile, die vom Kommentarformatierer von stackoverflow entfernt wird. Sie können sehen, dass die endgültige Ausgabe nach dem Ersetzen ein Zeichen für eine neue Zeile \nin den Wert einfügen sollte .
Fr0zenFyr
1
-1 Diese Antwort erstellt zuerst eine Zeichenfolge mit ungültigem JSON (da newline ein Steuerzeichen ist) und versucht dann, sie mit einer Reihe unvollständiger Ersetzungen zu beheben (es gibt mehr als 3 Steuerzeichen). Um das Ganze abzurunden, kann die evalFunktion auch verwendet werden. 17 positive Stimmen ???
Phil
1
Was ist mit Anführungszeichen, die ebenfalls maskiert werden müssen?
Stand Alone
8

Gemäß der Spezifikation http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf :

Eine Zeichenfolge ist eine Folge von Unicode-Codepunkten, die in Anführungszeichen ( U+0022) gesetzt sind. Alle Zeichen können in Anführungszeichen gesetzt werden, mit Ausnahme der Zeichen, die maskiert werden müssen: Anführungszeichen ( U+0022), umgekehrter Solidus ( U+005C) und die Steuerzeichen U+0000an U+001F. Es gibt zweistellige Escape-Sequenzdarstellungen einiger Zeichen.

Sie können also nicht direkt übergeben 0x0Aoder 0x0Ccodieren. Es ist verboten! Die Spezifikation schlägt vor, Escape-Sequenzen für einige genau definierte Codes von U+0000bis zu verwenden U+001F:

  • \frepräsentiert das Formular-Feed-Zeichen ( U+000C).
  • \nrepräsentiert das Zeilenvorschubzeichen ( U+000A).

Da die meisten Programmiersprachen \zum Zitieren verwenden, sollten Sie die Escape-Syntax umgehen (Double-Escape - einmal für Sprache / Plattform, einmal für JSON selbst):

jsonStr = "{ \"name\": \"Multi\\nline.\" }";
Gavenkoa
quelle
3

Sie können Ihre Zeichenfolge einfach auf dem Server maskieren, wenn Sie den Wert des JSON-Felds schreiben, und ihn beispielsweise beim Abrufen des Werts im Client-Browser entfernen.

Die JavaScript-Implementierung aller gängigen Browser verfügt über den Befehl unescape.

Beispiel:

Auf dem Server:

response.write "{""field1"":""" & escape(RS_Temp("textField")) & """}"

Im Browser:

document.getElementById("text1").value = unescape(jsonObject.field1)
Victor_Magalhaes
quelle
2

Vielleicht möchten Sie sich diese C # -Funktion ansehen, um der Zeichenfolge zu entkommen:

http://www.aspcode.net/C-encode-a-string-for-JSON-JavaScript.aspx

public static string Enquote(string s)  
{ 
    if (s == null || s.Length == 0)  
    { 
        return "\"\""; 
    } 
    char         c; 
    int          i; 
    int          len = s.Length; 
    StringBuilder sb = new StringBuilder(len + 4); 
    string       t; 

    sb.Append('"'); 
    for (i = 0; i < len; i += 1)  
    { 
        c = s[i]; 
        if ((c == '\\') || (c == '"') || (c == '>')) 
        { 
            sb.Append('\\'); 
            sb.Append(c); 
        } 
        else if (c == '\b') 
            sb.Append("\\b"); 
        else if (c == '\t') 
            sb.Append("\\t"); 
        else if (c == '\n') 
            sb.Append("\\n"); 
        else if (c == '\f') 
            sb.Append("\\f"); 
        else if (c == '\r') 
            sb.Append("\\r"); 
        else 
        { 
            if (c < ' ')  
            { 
                //t = "000" + Integer.toHexString(c); 
                string t = new string(c,1); 
                t = "000" + int.Parse(tmp,System.Globalization.NumberStyles.HexNumber); 
                sb.Append("\\u" + t.Substring(t.Length - 4)); 
            }  
            else  
            { 
                sb.Append(c); 
            } 
        } 
    } 
    sb.Append('"'); 
    return sb.ToString(); 
} 
Ron
quelle
3
Warum entkommt das >?
nichts ist notwendig
0

Ich habe diese Funktion verwendet, um Zeilenumbrüche oder andere Zeichen in Daten zu entfernen, um JSON-Daten zu analysieren:

function normalize_str($str) {

    $invalid = array(
        'Š'=>'S', 'š'=>'s',  'Đ'=>'Dj', 'đ'=>'dj', 'Ž'=>'Z', 'ž'=>'z',
        'Č'=>'C', 'č'=>'c',  'Ć'=>'C',  'ć'=>'c',  'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A',
        'Ä'=>'A', 'Å'=>'A',  'Æ'=>'A',  'Ç'=>'C',  'È'=>'E', 'É'=>'E', 'Ê'=>'E', 'Ë'=>'E',
        'Ì'=>'I', 'Í'=>'I',  'Î'=>'I',  'Ï'=>'I',  'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O',
        'Õ'=>'O', 'Ö'=>'O',  'Ø'=>'O',  'Ù'=>'U',  'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y',
        'Þ'=>'B', 'ß'=>'Ss', 'à'=>'a',  'á'=>'a',  'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a',
        'æ'=>'a', 'ç'=>'c',  'è'=>'e',  'é'=>'e',  'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i',
        'î'=>'i', 'ï'=>'i',  'ð'=>'o',  'ñ'=>'n',  'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o',
        'ö'=>'o', 'ø'=>'o',  'ù'=>'u',  'ú'=>'u',  'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b',
        'ÿ'=>'y', 'Ŕ'=>'R',  'ŕ'=>'r',
        "`" => "'", "´" => "'",  '"' => ',',  '`' => "'",
        '´' => "'", '"' => '\"', '"' => "\"", '´' => "'",
        "&acirc;€™" => "'",
        "{" => "",
        "~" => "",  "–" => "-",  "'" => "'",  "     " => " ");

    $str = str_replace(array_keys($invalid), array_values($invalid), $str);

    $remove = array("\n", "\r\n", "\r");
    $str = str_replace($remove, "\\n", trim($str));

    //$str = htmlentities($str, ENT_QUOTES);

    return htmlspecialchars($str);
}

echo normalize_str($lst['address']);
ShivarajRH
quelle
9
In den meisten Sprachen haben Sie bessere Möglichkeiten, Akzente von Unicode-Zeichenfolgen zu entfernen, als Ihre eigene Zuordnungsfunktion aufzuschreiben. Siehe diese Frage für ein Beispiel in Python: stackoverflow.com/questions/517923/…
MiniQuark
ya wir haben viele Möglichkeiten, die Sonderzeichen in verschiedenen Sprachen zu steuern.
ShivarajRH
2
Das ist alles schlecht, um sie im Allgemeinen auszuziehen. Codieren Sie sie besser als numerische XML-Zeichenreferenz und dekodieren Sie sie dann am Empfangsende.
Annarfych
0

JSON.stringify

JSON.stringify(`{ 
  a:"a"
}`)

würde die obige Zeichenfolge in konvertieren

"{ \n      a:\"a\"\n    }"

wie hier erwähnt

json stringify

Diese Funktion fügt am Anfang und Ende der Eingabezeichenfolge doppelte Anführungszeichen hinzu und maskiert JSON-Sonderzeichen. Insbesondere wird eine neue Zeile durch das Zeichen \ n ersetzt, eine Registerkarte wird durch das Zeichen \ t ersetzt, ein Backslash wird durch zwei Backslashes \ ersetzt und vor jedem Anführungszeichen wird ein Backslash gesetzt.

Mz A.
quelle
4
Dies ist eine Code-Antwort auf eine elf Jahre alte Frage mit acht weiteren vorhandenen Antworten. Es ist hilfreich, den Code zu erläutern und zu erläutern, welchen neuen Aspekt der Frage Ihre Antwort anspricht und ob sich der Zeitablauf und die Veröffentlichung neuer Versionen auf Ihre Antwort auswirken.
Jason Aller
-1

Ich bin auf dieses Problem gestoßen, als ich eine Klasse in PHP 4 erstellt habe, um json_encode zu emulieren (verfügbar in PHP 5). Folgendes habe ich mir ausgedacht:

class jsonResponse {
    var $response;

    function jsonResponse() {
        $this->response = array('isOK'=>'KO', 'msg'=>'Undefined');
    }

    function set($isOK, $msg) {
        $this->response['isOK'] = ($isOK) ? 'OK' : 'KO';
        $this->response['msg'] = htmlentities($msg);
    }

    function setData($data=null) {
        if(!is_null($data))
            $this->response['data'] = $data;
        elseif(isset($this->response['data']))
            unset($this->response['data']);
    }

    function send() {
        header('Content-type: application/json');
        echo '{"isOK":"' . $this->response['isOK'] . '","msg":' . $this->parseString($this->response['msg']);
        if(isset($this->response['data']))
            echo ',"data":' . $this->parseData($this->response['data']);
        echo '}';
    }

    function parseData($data) {
        if(is_array($data)) {
            $parsed = array();
            foreach ($data as $key=>$value)
                array_push($parsed, $this->parseString($key) . ':' . $this->parseData($value));
            return '{' . implode(',', $parsed) . '}';
        }
        else
            return $this->parseString($data);
    }

    function parseString($string) {
            $string = str_replace("\\", "\\\\", $string);
            $string = str_replace('/', "\\/", $string);
            $string = str_replace('"', "\\".'"', $string);
            $string = str_replace("\b", "\\b", $string);
            $string = str_replace("\t", "\\t", $string);
            $string = str_replace("\n", "\\n", $string);
            $string = str_replace("\f", "\\f", $string);
            $string = str_replace("\r", "\\r", $string);
            $string = str_replace("\u", "\\u", $string);
            return '"'.$string.'"';
    }
}

Ich habe die hier genannten Regeln befolgt . Ich habe nur das verwendet, was ich brauchte, aber ich denke, dass Sie es in der Sprache, die Sie verwenden, an Ihre Bedürfnisse anpassen können. Das Problem in meinem Fall war nicht, wie ich ursprünglich dachte, Newlines, sondern das / nicht entkommen. Ich hoffe, dies verhindert, dass jemand anderes die kleinen Kopfschmerzen hat, die ich hatte, um herauszufinden, was ich falsch gemacht habe.

GabrielP
quelle
2
Die auf json.org angegebenen 6 Abkürzungen für Steuerzeichen sind keine vollständige Liste aller Steuerzeichen. Infolgedessen kann diese Funktion ungültigen JSON generieren.
Phil
-5

Wie ich Ihnen Frage zu verstehen, ist es nicht über JSON Parsen , weil Sie Ihre JSON in Ihren Code direkt kopieren und einfügen können - so , wenn dies der Fall ist, dann richtet einfach kopieren Sie Ihre JSON ist dataObjvariabel , ohne es mit einfachen Anführungszeichen Einwickeln (Tipp: eval==evil)

var dataObj = {"count" : 1, "stack" : "sometext\n\n"};

console.log(dataObj);

Kamil Kiełczewski
quelle