¿Cómo manejo las nuevas líneas en JSON?

289

He generado algunos JSON y estoy tratando de ponerlo en un objeto en JavaScript. Sigo recibiendo errores. Esto es lo que tengo:

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

Esto me da un error:

unterminated string literal

Con JSON.parse(data), veo mensajes de error similares: " Unexpected token ↵" en Chrome y " unterminated string literal" en Firefox e IE.

Cuando saco el \ndespués, sometextel error desaparece en ambos casos. Parece que no puedo entender por qué las \nmarcas evaly JSON.parsefallan.

oso polar
fuente
19
Intente usar un analizador json real en lugar de eval.
Eric

Respuestas:

368

Supongo que esto es lo que quieres:

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

(Debe escapar de la "\" en su cadena (convirtiéndola en un doble - "\"), de lo contrario se convertirá en una nueva línea en la fuente JSON, no en los datos JSON).

BlaM
fuente
101
Por supuesto, esto es correcto, pero me gustaría agregar la razón para tener que hacer esto: la especificación JSON en ietf.org/rfc/rfc4627.txt contiene esta oración en la sección 2.5: "Todos los caracteres Unicode pueden colocarse dentro del comillas excepto los caracteres que se deben escapar: comillas, solidus inverso y los caracteres de control (U + 0000 a U + 001F) ". Como una nueva línea es un personaje de control, debe escapar.
daniel kullmann
1
De acuerdo con www.json.org, JSON acepta la secuencia de control "\ n" en cadenas, y si prueba JSON.parse (['"a \\ na"']) [1] .charCodeAt (); eso mostrará 10, que fue "Salto de línea" la última vez que lo verifiqué. --- Por cierto: ¡Deja de gritar!
BlaM
+ 1. Estaba teniendo problemas para entender la codificación JSON pero "se convertirá en una nueva línea en la fuente JSON, no en los datos JSON", me dejó claro.
amucunguzi
44

Usted tendrá que tener una función que sustituye \na \\nen caso de que datano es un literal de cadena.

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

El resultado dataObjserá

Object {count: 1, stack: "sometext\n\n"}
manish_s
fuente
3
necesita escapar de sus caracteres de escape (es decir .replace("\\n", "\\\\n")) y también sugeriría usar regex para permitir el reemplazo de varias instancias (es decir .replace(/\n/g, "\\\\n"))
musefan
2
¿Por qué necesitas escapar de los personajes de escape? Me refiero a algo como .replace("\n", "\\n")debería hacer el trabajo bien !! Por ejemplo, var test = [{"description":"Some description about the product. This can be multi-line text."}]; console.log(JSON.parse(test.replace(/\n/g, "\\n")));el objeto saldrá perfectamente bien a la consola del navegador como[{"description":"Some description about the product.\nThis can be multi-line text."}]
Fr0zenFyr
Por cierto, en el comentario anterior, la cadena JSON original tiene una nueva línea, que se elimina mediante el formateador de comentarios de stackoverflow. Puede ver que la salida final después de reemplazar debe insertar un carácter de nueva línea \nen el valor.
Fr0zenFyr
1
-1 Esta respuesta primero construye una cadena de JSON inválido (ya que la nueva línea es un carácter de control), luego trata de arreglarlo con una serie de reemplazos incompletos (hay más de 3 caracteres de control). Luego, para colmo, también logra usar la evalfunción. 17 votos a favor ???
Phil
1
¿Qué pasa con las comillas que también se deben escapar?
independiente
8

De acuerdo con la especificación, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf :

Una cadena es una secuencia de puntos de código Unicode envueltos con comillas ( U+0022). Todos los personajes pueden ser colocados dentro de las comillas, exceptuando el carácter que debe ser escapado: signo de comillas ( U+0022), barra inclinada invertida ( U+005C), y los caracteres de control U+0000a U+001F. Hay representaciones de secuencia de escape de dos caracteres de algunos caracteres.

Por lo tanto, no puede pasar 0x0Ao 0x0Ccodificar directamente. Está prohibido! La especificación sugiere utilizar secuencias de escape para algunos códigos bien definidos de U+0000a U+001F:

  • \frepresenta el carácter del feed del formulario ( U+000C).
  • \nrepresenta el carácter de avance de línea ( U+000A).

Como la mayoría de los lenguajes de programación usan \para las citas, debe escapar de la sintaxis de escape (doble escape: una vez para el lenguaje / plataforma, una vez para el propio JSON):

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

Podría simplemente escapar de su cadena en el servidor al escribir el valor del campo JSON y no escapar cuando recupere el valor en el navegador del cliente, por ejemplo.

La implementación de JavaScript de todos los principales navegadores tiene el comando unescape.

Ejemplo:

En el servidor:

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

En el navegador:

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

Es posible que desee examinar esta función de C # para escapar de la cadena:

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
fuente
3
¿Por qué se escapa esto >?
nada es necesario
0

Utilicé esta función para eliminar la nueva línea u otros caracteres en los datos para analizar los datos 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']);
ShivarajRH
fuente
9
En la mayoría de los idiomas, tiene mejores formas de quitar acentos de cadenas unicode que escribiendo su propia función de mapeo. Vea esta pregunta para ver un ejemplo en python: stackoverflow.com/questions/517923/…
MiniQuark
Ya tenemos muchas formas de controlar los caracteres especiales en idiomas diff.
ShivarajRH
2
Eso es bastante malo para despojarlos en general. Mejor codificarlos como referencia de caracteres numéricos XML y luego decodificar en el extremo receptor.
Annarfych
0

JSON.stringify

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

convertiría la cadena anterior a

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

como se menciona aquí

json stringify

Esta función agrega comillas dobles al principio y al final de la cadena de entrada y escapa caracteres JSON especiales. En particular, una nueva línea se reemplaza por el carácter \ n, una pestaña se reemplaza por el carácter \ t, una barra diagonal inversa se reemplaza por dos barras diagonales inversas \ y una barra diagonal inversa se coloca antes de cada comilla.

Mz A
fuente
44
Esta es una respuesta de solo código a una pregunta de once años con otras ocho respuestas existentes. Es útil para explicar el código, y también para explicar qué nuevo aspecto de la pregunta aborda su respuesta, y si el paso del tiempo y el lanzamiento de nuevas versiones impacta su respuesta.
Jason Aller
-1

Encontré ese problema al hacer una clase en PHP 4 para emular json_encode (disponible en PHP 5). Esto es lo que se me ocurrió:

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

Seguí las reglas mencionadas aquí . Solo usé lo que necesitaba, pero creo que puedes adaptarlo a tus necesidades en el idioma que estás utilizando. El problema en mi caso no era sobre las nuevas líneas como pensaba originalmente, sino sobre el / no escapar. Espero que esto evite que alguien más tenga el pequeño dolor de cabeza que tuve al descubrir lo que hice mal.

GabrielP
fuente
2
Las 6 abreviaturas para los caracteres de control especificados en json.org no son una lista exhaustiva de todos los caracteres de control. Como resultado, esta función podría generar JSON no válido.
Phil
-5

Como le he entendido la pregunta, no se trata de analizar JSON porque se puede copiar y pegar el JSON en su código directamente - por lo que si este es el caso, entonces sólo tienes que copiar el JSON de particular a dataObjvariable sin envolviéndolo con comillas simples (consejo: eval==evil)

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

console.log(dataObj);

Kamil Kiełczewski
fuente