Pouvez-vous utiliser une virgule de fin dans un objet JSON?

392

Lors de la génération manuelle d'un objet ou d'un tableau JSON, il est souvent plus facile de laisser une virgule de fin sur le dernier élément de l'objet ou du tableau. Par exemple, le code à sortir d'un tableau de chaînes pourrait ressembler (dans un pseudocode comme C ++):

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

vous donnant une chaîne comme

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

Est-ce permis?

Ben Combee
la source
66
C'était quelque chose que je devais rechercher sur le Web il y a quelques jours. Je n'ai pas vu de réponse ici sur SO, donc en suivant la mission du site, j'ai posé la question et y ai répondu pour que d'autres puissent la trouver. C'est quelque chose que Jeff a explicitement dit vouloir faire ici.
Ben Combee
5
Comme Jeff l'a dit, je pense que c'est parfaitement bien d'utiliser SO comme un «cahier» de choses que vous avez dû passer du temps à rechercher. Bien sûr, c'est à la fin de ces types d'articles, mais je pense toujours que c'est approprié, d'autant plus que différents moteurs javascript traiteront cela différemment.
pkaeding
6
Je me posais également la question, c'est donc une question parfaitement raisonnable.
hoju
48
Pour toutes ces salopes à qui quelqu'un a posé une question simple, veuillez vous retirer. Ce fut l'un des premiers succès sur Google, et cela m'a aidé à référencer rapidement la réponse. Merci OP.
40
Il est intéressant (ou horrible) dans IE 8 que je viens de trouver qui alert([1, 2, 3, ].length)affichera "4".
Daniel Earwicker

Réponses:

250

Malheureusement, la spécification JSON ne permet pas de virgule de fin. Il y a quelques navigateurs qui le permettront, mais généralement vous devez vous soucier de tous les navigateurs.

En général, j'essaie de contourner le problème et d'ajouter la virgule avant la valeur réelle, de sorte que vous vous retrouvez avec du code qui ressemble à ceci:

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("]");

Cette ligne de code supplémentaire dans votre boucle for n'est pas chère ...

Une autre alternative que j'ai utilisée lors de la sortie d'une structure en JSON à partir d'un dictionnaire d'une certaine forme consiste à toujours ajouter une virgule après chaque entrée (comme vous le faites ci-dessus), puis à ajouter une entrée fictive à la fin qui ne comporte pas de virgule de fin (mais c'est juste paresseux; ->).

Ne fonctionne pas bien avec un tableau malheureusement.

brianb
la source
2
J'ai commencé à utiliser cette mise en forme dans tout mon code JS (virgule avant l'élément sur la même ligne) pour exactement cette raison. Rend les virgules de fin supplémentaires beaucoup plus faciles à repérer et fait gagner beaucoup de temps. C'est ennuyeux, je souhaite qu'il y ait une option pour lancer une erreur pour cela avec Firefox (car cela aiderait au débogage).
rocketmonkeys
47
C'est vraiment dommage qu'ECMA5 spécifie les sentiers, mais pas JSON.
FlavorScape
4
Oui, cette ligne supplémentaire n'est pas chère, mais une nuisance néanmoins.
René Nyffenegger
2
Cette approche fonctionne pour les boucles for indexées. Et pour les boucles de style? Existe-t-il une manière élégante?
kgf3JfUtW
2
Cette ligne de code supplémentaire peut être compliquée lorsqu'il s'agit de propriétés. Vous pouvez vous retrouver avec des tonnes de ifs juste pour éviter cette stupide petite virgule. À propos du coût YMMV, voir par exemple jsfiddle.net/oriadam/mywL9384 Clarification: Votre solution est excellente, je déteste juste les spécifications qui interdisent une virgule de fin.
oriadam
133

Non. La spécification JSON, telle que maintenue sur http://json.org , n'autorise pas les virgules de fin. D'après ce que j'ai vu, certains analyseurs peuvent les autoriser en silence lors de la lecture d'une chaîne JSON, tandis que d'autres génèrent des erreurs. Pour l'interopérabilité, vous ne devez pas l'inclure.

Le code ci-dessus pourrait être restructuré, soit pour supprimer la virgule de fin lors de l'ajout du terminateur de tableau, soit pour ajouter la virgule avant les éléments, en sautant cela pour le premier.

Ben Combee
la source
1
ECMA 262 Semble le définir dans la section 11.1.5-Initialiseur d'objets. Que cela soit bon ou non, semble être dans la spécification.
Zero Distraction
6
Être ECMAScript valide ne signifie pas nécessairement qu'un document est JSON valide - JSON est généralement défini dans la RFC 4627 , et cette spécification n'autorise pas la virgule de fin.
Tim Gilbert
1
@ZeroDistraction: ECMA262 définit ECMAscript (également connu sous le nom de javascript) qui est un langage de programmation comme Perl ou Ruby ou C ++ ou Java. JSON est un format de données comme XML ou CSV ou YAML. Ce n'est pas la même chose. JSON n'existe pas dans EXMA262 mais la syntaxe dont il est dérivé existe et elle est appelée notation littérale de l'objet (ON dans JSON).
slebetman
106

Simple, bon marché, facile à lire et fonctionne toujours quelles que soient les spécifications.

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

L'affectation redondante à $ delim est un très petit prix à payer. Fonctionne aussi bien s'il n'y a pas de boucle explicite mais des fragments de code séparés.

Débordé
la source
1
C'est ce que je fais généralement dans des situations comme celle-ci; Je pense que l'affectation supplémentaire est plus que compensée en éliminant le conditionnel nécessaire pour ajouter la virgule avant la valeur dans l'approche alternative ( stackoverflow.com/a/201856/8946 ).
Lawrence Dol
5
Je n'aime pas cette solution, car il existe une autre variable polluant mon champ d'application. L'un ifest plus facile à saisir. Mais merci pour le partage.
Ich
3
En outre, il est préférable de contenir la portée du séparateur:for(let ..., sep=""; ... ; sep=",") { ...
Lawrence Dol
1
J'aime cette approche car elle évite les conditions, bien que les processeurs modernes aient une bonne logique de prédiction de branche. Voir aussi Pourquoi est-il plus rapide de traiter un tableau trié qu'un tableau non trié?
Hossein
21

Les virgules de fin sont autorisées en JavaScript, mais ne fonctionnent pas dans IE. Les spécifications JSON sans version de Douglas Crockford ne les autorisaient pas, et comme il était sans version, cela n'était pas censé changer. La spécification JSON ES5 les autorisait comme extension, mais le RFC 4627 de Crockford ne le permettait pas, et ES5 est revenu à les interdire. Firefox a emboîté le pas. Internet Explorer est la raison pour laquelle nous ne pouvons pas avoir de belles choses.

Tobu
la source
1
Je viens de les essayer dans IE 11 sans problème. Dans quelles versions d'IE avez-vous testé, où avez-vous constaté qu'elles causaient des problèmes?
iconoclaste du
10
On dirait que Crockford est la raison pour laquelle nous ne pouvons pas avoir de belles choses. Cela et commentaires dans JSON
Hejazzman
Pourquoi mentionner les navigateurs Web lorsque l'OP utilisait C ++ comme un pseudocode? Il est peu probable que la question du PO soit liée aux navigateurs Web ou à JavaScript.
Cowlinator
@cowlinator J ava S cript O bjet N ottaison
forresthopkinsa
1
Les littéraux d'objet Javascript ont inspiré le format, mais JSON n'est pas pour les moteurs Javascript
cowlinator
13

Comme cela a déjà été dit, la spécification JSON (basée sur ECMAScript 3) ne permet pas de virgule de fin. ES> = 5 le permet, vous pouvez donc réellement utiliser cette notation en JS pur. Il a été discuté et certains analyseurs l' ont soutenu ( http://bolinfest.com/essays/json.html , http://whereswalden.com/2010/09/08/spidermonkey-json-change-trailing-commas- n'est plus accepté / ), mais c'est le fait spécifique (comme indiqué sur http://json.org/ ) qu'il ne devrait pas fonctionner en JSON. Cette chose a dit ...

... Je me demande pourquoi personne n'a souligné que vous pouvez réellement diviser la boucle à la 0e itération et utiliser une virgule au lieu d'en suivre une pour se débarrasser de l'odeur du code de comparaison et de toute surcharge de performance réelle dans la boucle, ce qui entraîne un code qui est en fait plus court, plus simple et plus rapide (en raison de l'absence de branchement / conditions dans la boucle) que les autres solutions proposées.

Par exemple (dans un pseudocode de style C similaire au code proposé par 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("]");

la source
3
Exemple de code simple et rapide. Bien mieux que les solutions proposées par d'autres réponses.
Trevor Jex
12

Les codeurs PHP peuvent vouloir vérifier implode () . Cela prend un tableau le joint en utilisant une chaîne.

De la documentation ...

$array = array('lastname', 'email', 'phone');
echo implode(",", $array); // lastname,email,phone
Rik Heywood
la source
2
De même, JavaScript a join () . La plupart des langues ont une méthode similaire, ou une méthode similaire peut être facilement codée.
Dan Burton
16
PHP a json_encode, qui gère tous les détails de la création de JSON, pas seulement les virgules.
Brilliand
C'est super! Comment cela s'applique-t-il au JSON et comment aide-t-il le PO dans une résolution à leur question? Rappelez-vous, "Pouvez-vous utiliser une virgule de fin dans un objet JSON?" est la question.
Rockin4Life33
7

Fait intéressant, les deux C & C ++ (et je pense que C #, mais je ne suis pas sûr) autorisent spécifiquement la virgule de fin - pour exactement la raison donnée: Cela facilite la génération de listes par programmation. Je ne sais pas pourquoi JavaScript n'a pas suivi leur exemple.

James Curran
la source
13
L'ECMA a explicitement spécifié que les virgules de fin sont autorisées dans la spécification à venir: ejohn.org/blog/bug-fixes-in-javascript-2 Encore une autre raison pour être clair que JSON! = JS Object.
paupières
PHP le permet également. Je pense que c'est la seule fonctionnalité de PHP que j'aime. ; p
iconoclaste
4

Utilisez JSON5. N'utilisez pas JSON.

  • Les objets et les tableaux peuvent avoir des virgules de fin
  • Les clés d'objets peuvent être entre guillemets si elles sont des identifiants valides
  • Les chaînes peuvent être entre guillemets simples
  • Les chaînes peuvent être réparties sur plusieurs lignes
  • Les nombres peuvent être hexadécimaux (base 16)
  • Les nombres peuvent commencer ou se terminer par un point décimal (en tête ou en fin).
  • Les nombres peuvent inclure Infinity et -Infinity.
  • Les nombres peuvent commencer par un signe plus (+) explicite.
  • Les commentaires en ligne (sur une seule ligne) et en bloc (sur plusieurs lignes) sont autorisés.

http://json5.org/

https://github.com/aseemk/json5

user619271
la source
Ça a l'air bien, mais ne pas ajouter de nouveaux types de données semble être une occasion manquée ... bien sûr, le désir de rester un sous-ensemble strict d'ECMAScript 5 force cela, mais quand même ...
iconoclaste
1
De plus, les cordes mutlilines sont terribles. Je rêve des multilignes ES6.
Marco Sulla
10
Non, c'est un conseil HORRIBLE. De toutes les bibliothèques JSON existantes, très peu prennent en charge une telle extension; et tout cela pour des "améliorations" très discutables. Veuillez NE PAS provoquer une érosion supplémentaire de l'interopérabilité par de nouvelles extensions fausses comme celle-ci.
StaxMan
8
Je crois que passer sa vie à corriger des virgules est plus horrible.
user619271
3

Il existe un moyen possible d'éviter une if-branch dans la boucle.

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
la source
2

Selon la spécification de classe JSONArray :

  • Un supplément (virgule) peut apparaître juste avant le crochet de fermeture.
  • La valeur nulle sera insérée lorsqu'il y aura élision (virgule).

Donc, si je comprends bien, il devrait être permis d'écrire:

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

Mais il peut arriver que certains analyseurs renvoient le 7 comme nombre d'éléments (comme IE8 comme Daniel Earwicker l'a souligné) au lieu du 6 attendu.


Édité:

J'ai trouvé ce validateur JSON qui valide une chaîne JSON par rapport à RFC 4627 (le type de média application / json pour la notation d'objet JavaScript) et par rapport aux spécifications du langage JavaScript. En fait, ici, un tableau avec une virgule de fin est considéré comme valide uniquement pour JavaScript et non pour la spécification RFC 4627.

Cependant, dans la spécification RFC 4627, il est indiqué que:

2.3. Tableaux

Une structure de tableau est représentée par des crochets entourant zéro ou plusieurs valeurs (ou éléments). Les éléments sont séparés par des virgules.

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

Pour moi, c'est encore une fois un problème d'interprétation. Si vous écrivez que les éléments sont séparés par des virgules (sans mentionner quelque chose sur des cas particuliers, comme le dernier élément), cela pourrait être compris dans les deux sens.

PS RFC 4627 n'est pas une norme (comme indiqué explicitement), et est déjà obsolète par RFC 7159 (qui est une norme proposée) RFC 7159

Timoty Weis
la source
6
La règle de grammaire donnée est aussi précise que possible. Il n'y a aucun moyen d'avoir un value-separatorsans valuedroit à côté. Le texte est également très spécifique. La "séparation des valeurs" ne peut s'appliquer que s'il existe plusieurs valeurs. Donc, si vous avez deux valeurs côte à côte, elles sont séparées par une virgule. Si vous avez une valeur (ou si vous ne regardez que la valeur à la fin), il n'y a pas de séparation, donc pas de virgule.
Steffen Heil
1

D'après mon expérience passée, j'ai constaté que différents navigateurs traitent différemment les virgules de fin dans JSON.

Firefox et Chrome le gèrent très bien. Mais IE (toutes les versions) semble casser. Je veux dire vraiment casser et arrêter de lire le reste du script.

En gardant cela à l'esprit, et aussi le fait qu'il est toujours agréable d'écrire du code conforme, je suggère de dépenser l'effort supplémentaire pour s'assurer qu'il n'y a pas de virgule de fin.

:)

dnshio
la source
1

Je garde un décompte actuel et le compare à un décompte total. Si le nombre actuel est inférieur au nombre total, j'affiche la virgule.

Peut ne pas fonctionner si vous n'avez pas de nombre total avant d'exécuter la génération JSON.

Là encore, si vous utilisez PHP 5.2.0 ou mieux, vous pouvez simplement formater votre réponse en utilisant l'API JSON intégrée.

eddie
la source
1

Avec JSON détendu, vous pouvez avoir des virgules de fin, ou simplement laisser les virgules . Ils sont facultatifs.

Il n'y a aucune raison pour que les virgules soient présentes pour analyser un document de type JSON.

Jetez un œil à la spécification JSON détendue et vous verrez à quel point la spécification JSON originale est «bruyante». Beaucoup trop de virgules et de citations ...

http://www.relaxedjson.org

Vous pouvez également essayer votre exemple en utilisant cet analyseur RJSON en ligne et voir qu'il est analysé correctement.

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

Steven Spungin
la source
JSON détendu n'est pas JSON donc techniquement non applicable.
user2864740
Vous pouvez convertir rjson vers et depuis json, il est donc totalement applicable. Très facile à ajouter également à votre flux de travail.
Steven Spungin
Cela suppose que les consommateurs en aval comprennent ce non-JSON. La conversion en JSON valide nécessiterait la suppression de la virgule dans les deux cas.
user2864740
OP utilise une chaîne pour commencer. La chaîne peut être analysée en json objectutilisant JSON.parse, ou par une bibliothèque en utilisant RJSON.parse. Je serais d'accord avec vous si la source était un objet, mais ce n'est pas le cas ici. Je ne vois pas où dans la question il mentionne downstreamdu tout consommer un objet ou une chaîne.
Steven Spungin
"Lors de la génération manuelle d'un objet ou d'un tableau JSON , il est souvent plus facile de laisser une virgule de fin sur le dernier élément de l'objet ou du tableau. Est-ce autorisé [ dans JSON ]?" - donc, encore une fois: bien qu'il s'agisse d'un format alternatif intéressant, il n'est pas JSON et n'est pas techniquement applicable à la question sur JSON . Il n'y a rien à «défendre»: c'est une proposition de Z pour questionner X.
user2864740
0

Je boucle généralement sur le tableau et attache une virgule après chaque entrée de la chaîne. Après la boucle, je supprime à nouveau la dernière virgule.

Peut-être pas le meilleur moyen, mais moins cher que de vérifier à chaque fois s'il s'agit du dernier objet de la boucle, je suppose.

Nils
la source
0

Ce n'est pas recommandé, mais vous pouvez toujours faire quelque chose comme ça pour l'analyser.

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

feibing
la source
0

Puisqu'une boucle for est utilisée pour itérer sur un tableau, ou une structure de données itérable similaire, nous pouvons utiliser la longueur du tableau comme indiqué,

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

Avec datafile.txt contenant,

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

Comme indiqué, ce n'est pas autorisé. Mais en JavaScript, c'est:

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

(fonctionne bien dans Firefox, Chrome, Edge, IE11 et sans le laisser dans IE9, 8, 7, 5)

theking2
la source