Come gestisco le newline in JSON?


289

Ho generato alcuni JSON e sto cercando di inserirlo in un oggetto in JavaScript. Continuo a ricevere errori. Ecco cosa ho:

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

Questo mi dà un errore:

unterminated string literal

Con JSON.parse(data), vedo messaggi di errore simili: " Unexpected token ↵" in Chrome e " unterminated string literal" in Firefox e IE.

Quando tolgo il \ndopo sometextl'errore scompare in entrambi i casi. Non riesco a capire il motivo per cui il \nmake evaland JSON.parsefail.


19
Prova a usare un vero parser json invece di eval.
Eric

Risposte:


369

Immagino che questo sia quello che vuoi:

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

(È necessario sfuggire al "\" nella stringa (trasformandolo in un doppio - "\"), altrimenti diventerà una nuova riga nell'origine JSON, non i dati JSON.)


101
Questo è ovviamente corretto, ma vorrei aggiungere il motivo per cui è necessario farlo: la specifica JSON su ietf.org/rfc/rfc4627.txt contiene questa frase nella sezione 2.5: "Tutti i caratteri Unicode possono essere inseriti all'interno del virgolette ad eccezione dei caratteri che devono essere sfuggiti: virgolette, punto inverso e caratteri di controllo (da U + 0000 a U + 001F). " Poiché una newline è un personaggio di controllo, deve essere sfuggita.
daniel kullmann,

1
Secondo www.json.org JSON accetta la sequenza di controllo "\ n" nelle stringhe - e se provi JSON.parse (['"a \\ na"']) [1] .charCodeAt (); che mostrerà 10 - che era "Linefeed" l'ultima volta che ho controllato. --- A proposito: smetti di urlare!
BlaM,

+ 1. Ho avuto difficoltà a comprendere la codifica JSON ma "diventerà una nuova riga nella fonte JSON, non i dati JSON" mi ha chiarito.
amucunguzi,

44

Avrete bisogno di avere una funzione che sostituisce \na \\nnel caso in cui datanon è un letterale stringa.

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));

Il risultato dataObjsarà

Object {count: 1, stack: "sometext\n\n"}

3
devi scappare dai tuoi personaggi di escape (es. .replace("\\n", "\\\\n")) e ti suggerirei anche di usare regex per consentire la sostituzione di più istanze (es. .replace(/\n/g, "\\\\n"))
musefan

2
perché hai bisogno di sfuggire ai personaggi di fuga? Voglio dire qualcosa come .replace("\n", "\\n")dovrebbe fare bene il lavoro !! Ad esempio, var test = [{"description":"Some description about the product. This can be multi-line text."}]; console.log(JSON.parse(test.replace(/\n/g, "\\n")));produrrà l'oggetto perfettamente bene sulla console del browser come[{"description":"Some description about the product.\nThis can be multi-line text."}]
Fr0zenFyr,

A proposito, nel commento sopra, la stringa JSON originale ha una nuova riga, che viene rimossa dal formattatore dei commenti di stackoverflow. Puoi vedere che l'output finale dopo la sostituzione dovrebbe inserire un carattere di nuova riga \nnel valore.
Fr0zenFyr,

1
-1 Questa risposta costruisce prima una stringa di JSON non validi (poiché newline è un carattere di controllo), quindi tenta di risolverlo con una serie di sostituzioni incomplete (sono presenti più di 3 caratteri di controllo). Quindi, per finire, riesce anche a utilizzare la evalfunzione. 17 voti ???
Phil

1
Che dire delle virgolette che devono essere sfuggite anche?
stand alone

8

Secondo le specifiche, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf :

Una stringa è una sequenza di punti di codice Unicode racchiusi tra virgolette ( U+0022). Tutti i caratteri possono essere inseriti tra virgolette ad eccezione dei caratteri che devono essere sfuggiti: virgolette ( U+0022), reverse solidus ( U+005C) e i caratteri di controllo U+0000perU+001F . Esistono rappresentazioni di sequenze di escape a due caratteri di alcuni personaggi.

Quindi non puoi passare 0x0Ao 0x0Ccodici direttamente. È vietato! La specifica suggerisce di utilizzare sequenze di escape per alcuni codici ben definiti da U+0000a U+001F:

  • \frappresenta il carattere di feed del modulo ( U+000C).
  • \nrappresenta il carattere di avanzamento riga ( U+000A).

Poiché la maggior parte dei linguaggi di programmazione utilizza \per il preventivo, è necessario evitare la sintassi di escape (double-escape - una volta per linguaggio / piattaforma, una volta per JSON stesso):

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

3

Potresti semplicemente sfuggire alla tua stringa sul server durante la scrittura del valore del campo JSON e annullarla durante il recupero del valore nel browser client, ad esempio.

L'implementazione JavaScript di tutti i principali browser ha il comando unescape.

Esempio:

Sul server:

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

Nel browser:

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

2

Potresti voler esaminare questa funzione C # per sfuggire alla stringa:

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(); 
} 

3
Perché questa fuga >?
nothingisnecessary

0

Ho usato questa funzione per eliminare la nuova riga o altri caratteri nei dati per analizzare i dati JSON:

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']);

9
Nella maggior parte delle lingue hai modi migliori per eliminare gli accenti dalle stringhe unicode piuttosto che scrivere la tua funzione di mappatura. Vedere questa domanda per un esempio in python: stackoverflow.com/questions/517923/...
MiniQuark

ya abbiamo molti modi per controllare i caratteri speciali nelle lingue diff.
ShivarajRH,

2
È tutto negativo per spogliarli in generale. Meglio codificarli come riferimento di caratteri numerici XML e quindi decodificarli alla fine della ricezione.
Annarfych,

0

JSON.stringify

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

converte la stringa sopra in

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

come menzionato qui

json stringify

Questa funzione aggiunge virgolette all'inizio e alla fine della stringa di input e sfugge ai caratteri JSON speciali. In particolare, una nuova riga viene sostituita dal carattere \ n, una scheda viene sostituita dal carattere \ t, una barra rovesciata viene sostituita da due barre rovesciate \ e una barra rovesciata viene posizionata prima di ogni virgoletta.


4
Questo è un codice che risponde solo a una domanda di undici anni con altre otto risposte esistenti. È utile spiegare il codice e anche spiegare quale nuovo aspetto della domanda affronta la tua risposta e se il passare del tempo e il rilascio di nuove versioni influiscono sulla tua risposta.
Jason Aller il

-1

Ho riscontrato questo problema durante la creazione di una classe in PHP 4 per emulare json_encode (disponibile in PHP 5). Ecco cosa mi è venuto in mente:

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.'"';
    }
}

Ho seguito le regole menzionate qui . Ho usato solo ciò di cui avevo bisogno, ma immagino che tu possa adattarlo alle tue esigenze nella lingua che stai usando. Il problema nel mio caso non riguardava le newline come pensavo inizialmente, ma il fatto di non essere evaso. Spero che questo prevenga qualcun altro dal piccolo mal di testa che ho avuto per capire cosa ho fatto di sbagliato.


2
I 6 shorthands per i personaggi di controllo specificati su json.org non sono un elenco esaustivo di tutti i personaggi di controllo. Di conseguenza, questa funzione potrebbe generare JSON non valido.
Phil

-5

Come ho capito domanda, non si tratta di analisi JSON, perché è possibile copiare e incollare il tuo JSON nel codice direttamente - quindi se questo è il caso, allora basta copiare il JSON direttamente a dataObjvariabile senza avvolgendolo con apici (suggerimento: eval==evil)

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

console.log(dataObj);

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.