¿Se puede usar una coma final en un objeto JSON?

392

Al generar manualmente un objeto o matriz JSON, a menudo es más fácil dejar una coma final en el último elemento del objeto o matriz. Por ejemplo, el código de salida de una matriz de cadenas podría verse así (en un pseudocódigo similar a C ++):

s.append("[");
for (i = 0; i < 5; ++i) {
    s.appendF("\"%d\",", i);
}
s.append("]");

dándote una cuerda como

[0,1,2,3,4,5,]

¿Esto está permitido?

Ben Combee
fuente
66
Era algo que necesitaba buscar en la web hace unos días. No vi una respuesta aquí en SO, así que al seguir la misión del sitio, planteé la pregunta y la respondí para que otros pudieran encontrarla. Esto es algo que Jeff dijo explícitamente que quería hacer aquí.
Ben Combee
55
Como Jeff dijo, creo que está perfectamente bien usar SO como un "cuaderno" de cosas que tenía que pasar algún tiempo buscando. Claro, esto está en el extremo simple de ese tipo de elementos, pero todavía creo que es apropiado, especialmente porque los diferentes motores javascript tratarán esto de manera diferente.
pkaeding
66
También me preguntaba esto, por lo que es una pregunta perfectamente razonable.
hoju
48
Para todos los quejidos de que alguien hizo una pregunta simple, por favor retroceda. Este fue uno de los primeros éxitos en Google, y me ayudó a hacer referencia a la respuesta rápidamente. Gracias OP.
40
Curiosamente (o horripilante) en IE 8, acabo de encontrar que alert([1, 2, 3, ].length)mostrará "4".
Daniel Earwicker

Respuestas:

250

Lamentablemente, la especificación JSON no permite una coma final. Hay algunos navegadores que lo permitirán, pero generalmente debe preocuparse por todos los navegadores.

En general, trato de resolver el problema y agrego la coma antes del valor real, para que termines con un código similar al siguiente:

s.append("[");
for (i = 0; i < 5; ++i) {
  if (i) s.append(","); // add the comma only if this isn't the first entry
  s.appendF("\"%d\"", i);
}
s.append("]");

Esa línea adicional de código en su bucle for no es cara ...

Otra alternativa que he usado al generar una estructura para JSON desde un diccionario de alguna forma es agregar siempre una coma después de cada entrada (como lo está haciendo anteriormente) y luego agregar una entrada ficticia al final que no tiene coma (pero eso es simplemente vago; ->).

Desafortunadamente, no funciona bien con una matriz.

brianb
fuente
2
He comenzado a usar este formato en todo mi código JS (coma antes del elemento en la misma línea) exactamente por esta razón. Hace que las comas finales adicionales sean mucho más fáciles de detectar y ahorra mucho tiempo. Es molesto, desearía que hubiera una opción para lanzar un error para esto con firefox (ya que eso ayudaría con la depuración).
rocketmonkeys
47
Es realmente una pena que ECMA5 especifique rutas, pero JSON no.
FlavorScape
44
Sí, esa línea extra no es cara, pero es una molestia.
René Nyffenegger
2
Este enfoque funciona para bucles for indexados. ¿Qué tal para ... en bucles de estilo? ¿Hay alguna manera elegante?
kgf3JfUtW
2
Esa línea adicional de código puede ser complicada cuando se trata de propiedades. Es posible que tenga toneladas de ifs solo para evitar esa estúpida pequeña coma. Sobre el YMMV caro, vea esto por ejemplo jsfiddle.net/oriadam/mywL9384 Aclaración: Su solución es excelente, simplemente odio las especificaciones que prohíben una coma final.
oriadam
133

No. La especificación JSON, como se mantiene en http://json.org , no permite las comas finales. Por lo que he visto, algunos analizadores pueden permitirlos en silencio al leer una cadena JSON, mientras que otros arrojarán errores. Para la interoperabilidad, no debe incluirlo.

El código anterior podría reestructurarse, ya sea para eliminar la coma final al agregar el terminador de matriz o para agregar la coma antes de los elementos, omitiendo eso para el primero.

Ben Combee
fuente
1
ECMA 262 parece definirlo en la sección 11.1.5-Inicializador de objetos. Si esto es bueno o no, parece estar en la especificación.
Cero distracción
66
Ser válido ECMAScript no significa necesariamente que un documento sea válido JSON: JSON generalmente se define en RFC 4627 , y esa especificación no permite la coma final.
Tim Gilbert
1
@ZeroDistraction: ECMA262 define ECMAscript (también conocido como javascript), que es un lenguaje de programación como Perl o Ruby o C ++ o Java. JSON es un formato de datos como XML o CSV o YAML. No són la misma cosa. JSON no existe en EXMA262, pero la sintaxis de la que deriva y sí se llama notación literal de objeto (ON en JSON).
slebetman
106

Simple, barato, fácil de leer y siempre funciona independientemente de las especificaciones.

$delimiter = '';
for ....  {
    print $delimiter.$whatever
    $delimiter = ',';
}

La asignación redundante a $ delim es un precio muy pequeño a pagar. También funciona igual de bien si no hay un bucle explícito sino fragmentos de código separados.

Overflowee
fuente
1
Eso es lo que normalmente hago en situaciones como esta; Siento que la asignación adicional está más que compensada al eliminar el condicional necesario para agregar la coma antes del valor en el enfoque alternativo ( stackoverflow.com/a/201856/8946 ).
Lawrence Dol
55
No me gusta esta solución, ya que hay otra variable que contamina mi alcance. Uno ifes más fácil de entender. Pero gracias por compartir.
Ich
3
Además, es mejor contener el alcance del separador:for(let ..., sep=""; ... ; sep=",") { ...
Lawrence Dol
1
Me gusta este enfoque porque evita los condicionales, aunque las CPU modernas tienen una buena lógica de predicción de rama. Consulte también ¿Por qué es más rápido procesar una matriz ordenada que una matriz sin clasificar?
Hossein
21

Las comillas finales están permitidas en JavaScript, pero no funcionan en IE. La especificación JSON sin versión de Douglas Crockford no los permitía, y debido a que no tenía versión, se suponía que esto no cambiaría. La especificación JSON de ES5 los permitió como una extensión, pero el RFC 4627 de Crockford no lo hizo, y ES5 volvió a rechazarlos. Firefox hizo lo mismo. Internet Explorer es la razón por la que no podemos tener cosas buenas.

Tobu
fuente
1
Acabo de probarlos en IE 11 sin ningún problema. ¿En qué versiones de IE has probado, donde descubriste que causan problemas?
iconoclasta
10
Parece que Crockford es la razón por la que no podemos tener cosas buenas. Eso y comentarios en JSON
Hejazzman
¿Por qué mencionar los navegadores web cuando el OP usaba C ++ como pseudocódigo? Es poco probable que la pregunta del OP esté relacionada con los navegadores web o JavaScript.
cowlinator
@cowlinator J ava S cript O bject N otation
forresthopkinsa
1
Los literales de objetos Javascript inspiraron el formato, pero JSON no es para motores Javascript
cowlinator
13

Como ya se ha dicho, la especificación JSON (basada en ECMAScript 3) no permite la coma final. ES> = 5 lo permite, por lo que puede usar esa notación en JS puro. Se ha discutido al respecto, y algunos analizadores sí lo soportaron ( http://bolinfest.com/essays/json.html , http://whereswalden.com/2010/09/08/spidermonkey-json-change-trailing-commas- no más aceptado / ), pero es el hecho de la especificación (como se muestra en http://json.org/ ) que no debería funcionar en JSON. Esa cosa dijo ...

... Me pregunto por qué nadie señaló que en realidad se puede dividir el bucle en iteración 0 y el uso que conduce coma inicial en lugar de seguir uno para deshacerse del olor del código de comparación y cualquier sobrecarga de rendimiento real en el ciclo, lo que resulta en un código que en realidad es más corto, más simple y más rápido (debido a que no hay ramificaciones / condicionales en el ciclo) que otras soluciones propuestas.

Por ejemplo (en un pseudocódigo de estilo C similar al código propuesto de OP):

s.append("[");
// MAX == 5 here. if it's constant, you can inline it below and get rid of the comparison
if ( MAX > 0 ) {
    s.appendF("\"%d\"", 0); // 0-th iteration
    for( int i = 1; i < MAX; ++i ) {
        s.appendF(",\"%d\"", i); // i-th iteration
    }
}
s.append("]");

fuente
3
Ejemplo de código simple y rápido. Mucho mejor que las soluciones propuestas por otras respuestas.
Trevor Jex
12

Los codificadores PHP pueden querer revisar implode () . Esto toma una matriz que la une usando una cadena.

De los documentos ...

$array = array('lastname', 'email', 'phone');
echo implode(",", $array); // lastname,email,phone
Rik Heywood
fuente
2
Del mismo modo, JavaScript tiene join () . La mayoría de los idiomas tienen un método similar, o uno similar puede codificarse fácilmente.
Dan Burton
16
PHP tiene json_encode, que maneja todos los detalles de hacer JSON, no solo comas.
Brilliand
¡Eso es genial! ¿Cómo se aplica a JSON y cómo ayuda al OP en una resolución a su pregunta? Recuerde, "¿Puede usar una coma final en un objeto JSON?" es la pregunta.
Rockin4Life33
7

Curiosamente, tanto C como C ++ (y creo que C #, pero no estoy seguro) permiten específicamente la coma final, por exactamente la razón dada: hace que la generación programática de listas sea mucho más fácil. No estoy seguro de por qué JavaScript no siguió su ejemplo.

James Curran
fuente
13
ECMA ha especificado explícitamente que las comas finales están permitidas en la próxima especificación: ejohn.org/blog/bug-fixes-in-javascript-2 Otra razón más para dejar en claro que JSON! = JS Object.
párpados
PHP también lo permite. Creo que es la única característica de PHP que me gusta. ; p
iconoclasta
4

Utiliza JSON5. No uses JSON.

  • Los objetos y las matrices pueden tener comas finales
  • Las claves de objeto pueden ser sin comillas si son identificadores válidos
  • Las cadenas pueden ser entre comillas simples
  • Las cadenas se pueden dividir en varias líneas
  • Los números pueden ser hexadecimales (base 16)
  • Los números pueden comenzar o terminar con un punto decimal (inicial o final).
  • Los números pueden incluir Infinito e -Infinito.
  • Los números pueden comenzar con un signo más (+) explícito.
  • Se permiten comentarios tanto en línea (una línea) como en bloque (varias líneas).

http://json5.org/

https://github.com/aseemk/json5

usuario619271
fuente
Se ve bien, pero no la adición de nuevos tipos de datos parece una oportunidad perdida ... por supuesto, el deseo de seguir siendo un subconjunto estricto de ECMAScript 5 fuerzas que, pero aún así ...
iconoclasta
1
Además, las cuerdas mutliline son terribles. Sueño con ES6 multilíneas.
Marco Sulla
10
No, ese es un consejo HORRIBLE. De todas las bibliotecas JSON existentes, muy pocas admiten dicha extensión; y todo esto para "mejoras" muy cuestionables. NO provoque una mayor erosión de la interoperabilidad por nuevas extensiones falsas como esta.
StaxMan
8
Creo que pasar tu vida arreglando comas es más horrible.
user619271
3

Hay una manera posible de evitar una rama if en el bucle.

s.append("[ "); // there is a space after the left bracket
for (i = 0; i < 5; ++i) {
  s.appendF("\"%d\",", i); // always add comma
}
s.back() = ']'; // modify last comma (or the space) to right bracket
Zhang Boyang
fuente
2

De acuerdo con la especificación Clase JSONArray :

  • Puede aparecer un (coma) adicional justo antes del corchete de cierre.
  • El valor nulo se insertará cuando haya, (coma) elisión.

Entonces, según tengo entendido, debería permitirse escribir:

[0,1,2,3,4,5,]

Pero podría suceder que algunos analizadores devuelvan el 7 como recuento de elementos (como IE8 como señaló Daniel Earwicker) en lugar del esperado 6.


Editado:

Encontré este Validador JSON que valida una cadena JSON contra RFC 4627 (el tipo de medio de aplicación / json para la notación de objetos JavaScript) y contra la especificación del lenguaje JavaScript. En realidad, aquí una matriz con una coma final se considera válida solo para JavaScript y no para la especificación RFC 4627.

Sin embargo, en la especificación RFC 4627 se afirma que:

2.3. Matrices

Una estructura de matriz se representa entre corchetes que rodean cero o más valores (o elementos). Los elementos están separados por comas.

array = begin-array [ value *( value-separator value ) ] end-array

Para mí esto es nuevamente un problema de interpretación. Si escribe que los Elementos están separados por comas (sin indicar algo sobre casos especiales, como el último elemento), podría entenderse de ambas maneras.

PS RFC 4627 no es un estándar (como se indica explícitamente), y ya está obstruido por RFC 7159 (que es un estándar propuesto) RFC 7159

Timoty Weis
fuente
66
La regla gramatical dada es lo más precisa posible. No hay forma de tener un value-separatorsin valuederecho al lado. También el texto es muy específico. La "separación de valores" solo puede aplicarse si hay varios valores. Entonces, si tiene dos valores uno al lado del otro, se separan mediante una coma. Si tiene un valor (o si solo mira el valor al final), no hay separación, por lo tanto, no hay coma.
Steffen Heil
1

Desde mi experiencia pasada, descubrí que diferentes navegadores tratan las comas finales en JSON de manera diferente.

Tanto Firefox como Chrome lo manejan bien. Pero IE (Todas las versiones) parece romperse. Me refiero a realmente romper y dejar de leer el resto del guión.

Teniendo esto en cuenta, y también el hecho de que siempre es bueno escribir código compatible, sugiero que se dedique un esfuerzo adicional para asegurarse de que no haya una coma final.

:)

dnshio
fuente
1

Mantengo un conteo actual y lo comparo con un conteo total. Si el recuento actual es menor que el recuento total, visualizo la coma.

Es posible que no funcione si no tiene un recuento total antes de ejecutar la generación JSON.

Por otra parte, si está utilizando PHP 5.2.0 o superior, puede formatear su respuesta utilizando la API JSON incorporada.

Eddie
fuente
1

Con Relaxed JSON, puede tener comas finales, o simplemente dejar las comas fuera . Son opcionales.

No hay ninguna razón para que todas las comas necesiten estar presentes para analizar un documento similar a JSON.

Eche un vistazo a la especificación JSON relajada y verá cuán 'ruidosa' es la especificación JSON original. Demasiadas comas y citas ...

http://www.relaxedjson.org

También puede probar su ejemplo usando este analizador RJSON en línea y ver que se analiza correctamente.

http://www.relaxedjson.org/docs/converter.html?source=%5B0%2C1%2C2%2C3%2C4%2C5%2C%5D

Steven Spungin
fuente
JSON relajado no es JSON técnicamente no aplicable.
user2864740
Puede convertir rjson desde y hacia json, por lo que es totalmente aplicable. Muy fácil de agregar a su flujo de trabajo también.
Steven Spungin el
Esto supone que los consumidores intermedios entienden este no JSON. La conversión a un JSON válido requeriría eliminar la coma en cualquier caso.
usuario2864740
OP utiliza una cadena para comenzar. La cadena puede ser analizada a un json objectuso JSON.parse, o por una biblioteca usando RJSON.parse. Estaría de acuerdo con usted si la fuente fuera un objeto, pero ese no es el caso aquí. No veo en qué parte de la pregunta se menciona downstreamconsumir un objeto o una cadena.
Steven Spungin
"Al generar manualmente un objeto o matriz JSON , a menudo es más fácil dejar una coma final en el último elemento del objeto o matriz ... ¿Está permitido [ en JSON ]?" - Entonces, de nuevo: si bien este es un formato alternativo interesante, no es JSON y técnicamente no es aplicable a la pregunta sobre JSON . No hay nada que 'defender': es una propuesta Z para cuestionar X.
user2864740
0

Por lo general, hago un bucle sobre la matriz y adjunto una coma después de cada entrada en la cadena. Después del ciclo borro la última coma nuevamente.

Tal vez no sea la mejor manera, pero supongo que es menos costoso que comprobar cada vez si es el último objeto del bucle.

Nils
fuente
0

No se recomienda, pero aún puede hacer algo como esto para analizarlo.

jsonStr = '[0,1,2,3,4,5,]';
let data;
eval('data = ' + jsonStr);
console.log(data)

feibing
fuente
0

Dado que un bucle for se usa para iterar sobre una matriz, o una estructura de datos iterable similar, podemos usar la longitud de la matriz como se muestra,

awk -v header="FirstName,LastName,DOB" '
  BEGIN {
    FS = ",";
    print("[");
    columns = split(header, column_names, ",");
  }
  { print("  {");
    for (i = 1; i < columns; i++) {
      printf("    \"%s\":\"%s\",\n", column_names[i], $(i));
    }
    printf("    \"%s\":\"%s\"\n", column_names[i], $(i));
    print("  }");
  }
  END { print("]"); } ' datafile.txt

Con datafile.txt que contiene,

 Angela,Baker,2010-05-23
 Betty,Crockett,1990-12-07
 David,Done,2003-10-31
Gregory Horne 07AD
fuente
0

Como se dijo, no está permitido. Pero en JavaScript esto es:

var a = Array()
for(let i=1; i<=5; i++) {
    a.push(i)
}
var s = "[" + a.join(",") + "]"

(funciona bien en Firefox, Chrome, Edge, IE11 y sin el permiso en IE9, 8, 7, 5)

theking2
fuente