Czy możesz użyć końcowego przecinka w obiekcie JSON?

392

Podczas ręcznego generowania obiektu lub tablicy JSON często łatwiej jest pozostawić przecinek końcowy na ostatnim elemencie w obiekcie lub tablicy. Na przykład kod wyjściowy z tablicy ciągów może wyglądać (w pseudokodzie typu C ++):

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

dając ci ciąg jak

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

Czy to jest dozwolone?

Ben Combee
źródło
66
To było coś, co musiałem wyszukać w Internecie kilka dni temu. Nie widziałem tutaj odpowiedzi na SO, więc podążając za misją strony, zadałem pytanie i odpowiedziałem, aby inni mogli je znaleźć. Jest to coś, co Jeff wyraźnie powiedział, że chce tutaj zrobić.
Ben Combee
5
Jak powiedział Jeff, myślę, że doskonale jest używać SO jako „notesu” rzeczy, które musiałeś poświęcić na wyszukiwanie. Jasne, to jest po prostu koniec tego rodzaju przedmiotów, ale nadal uważam, że jest to właściwe, zwłaszcza że różne silniki javascript radzą sobie z tym inaczej.
pkaeding
6
Zastanawiałem się również nad tym, więc jest to całkowicie rozsądne pytanie.
hoju
48
Wszystkim tym dziwkom, którym ktoś zadał proste pytanie, proszę się wycofać. To był jeden z pierwszych hitów w Google i pomógł mi szybko znaleźć odpowiedź. Dziękuję OP.
40
Co ciekawe (lub przerażająco) w IE 8 właśnie znalazłem, że alert([1, 2, 3, ].length)wyświetli „4”.
Daniel Earwicker,

Odpowiedzi:

250

Niestety specyfikacja JSON nie pozwala na przecinek końcowy. Istnieje kilka przeglądarek, które na to pozwolą, ale ogólnie musisz martwić się o wszystkie przeglądarki.

Ogólnie staram się odwrócić problem i dodać przecinek przed rzeczywistą wartością, aby uzyskać kod wyglądający następująco:

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

Ta dodatkowa linia kodu w pętli for nie jest droga ...

Inną alternatywą, której użyłem, gdy wypisałem strukturę do JSON ze słownika jakiejś formy, jest zawsze dodawanie przecinka po każdym wpisie (jak to robisz powyżej), a następnie dodanie fikcyjnego wpisu na końcu, który nie ma przecinka (ale to jest po prostu leniwe; ->).

Niestety nie działa dobrze z tablicą.

Brianb
źródło
2
Właśnie z tego powodu zacząłem używać tego formatowania w całym kodzie JS (przecinek przed pozycją w tym samym wierszu). Znacznie ułatwia wykrycie dodatkowych przecinków i pozwala zaoszczędzić dużo czasu. To denerwujące, chciałbym, aby istniała możliwość zgłoszenia błędu w firefoxie (ponieważ pomogłoby to w debugowaniu).
rocketmonkeys
47
Szkoda, że ​​ECMA5 określa trasy, ale JSON tego nie robi.
FlavorScape,
4
Tak, ta dodatkowa linia nie jest droga, ale mimo to uciążliwa.
René Nyffenegger
2
To podejście działa w przypadku indeksowanych pętli for. Co powiesz na ... w stylowych pętlach? Czy istnieje elegancki sposób?
kgf3JfUtW
2
Ten dodatkowy wiersz kodu może być skomplikowany w przypadku właściwości. Możesz mieć mnóstwo ifs, aby uniknąć tego głupiego małego przecinka. O kosztowności YMMV, zobacz to na przykład jsfiddle.net/oriadam/mywL9384 Wyjaśnienie: Twoje rozwiązanie jest świetne, po prostu nienawidzę specyfikacji, które zabraniają przecinku końcowego.
oriadam
133

Nie. Specyfikacja JSON, utrzymywana na stronie http://json.org , nie zezwala na końcowe przecinki. Z tego, co widziałem, niektóre parsery mogą po cichu na to pozwolić podczas czytania łańcucha JSON, podczas gdy inne będą zgłaszać błędy. Aby zapewnić interoperacyjność, nie należy go uwzględniać.

Powyższy kod można zrestrukturyzować, aby usunąć przecinek końcowy podczas dodawania terminatora tablicowego lub dodać przecinek przed elementami, pomijając ten dla pierwszego.

Ben Combee
źródło
1
ECMA 262 Zdaje się to definiować w sekcji 11.1.5 - Inicjator obiektów. Wygląda na to, czy jest to dobre, czy nie.
zero rozproszenia
6
Bycie poprawnym ECMAScript nie musi oznaczać, że dokument jest prawidłowy JSON - JSON jest ogólnie zdefiniowany w RFC 4627 i ta specyfikacja nie pozwala na przecinek końcowy.
Tim Gilbert,
1
@ZeroDistraction: ECMA262 definiuje ECMAscript (znany również jako javascript), który jest językiem programowania takim jak Perl lub Ruby lub C ++ lub Java. JSON jest formatem danych, takim jak XML, CSV lub YAML. To nie to samo. JSON nie istnieje w EXMA262, ale ma składnię, z której pochodzi, i jest nazywany notacją dosłowną Object (ON w JSON).
slebetman
106

Prosty, tani, łatwy do odczytania i zawsze działa niezależnie od specyfikacji.

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

Nadmiarowe przypisanie do $ delim to bardzo niewielka cena do zapłaty. Działa równie dobrze, jeśli nie ma wyraźnej pętli, ale oddzielne fragmenty kodu.

Przepełnienie
źródło
1
Tak zwykle robię w takich sytuacjach; Wydaje mi się, że dodatkowe przypisanie jest więcej niż wyrównane poprzez wyeliminowanie warunku potrzebnego do dodania przecinka przed wartością w alternatywnym podejściu ( stackoverflow.com/a/201856/8946 ).
Lawrence Dol
5
Nie podoba mi się to rozwiązanie, ponieważ moja zmienna zanieczyszcza inną zmienną. Jedno ifjest łatwiejszy do uchwycenia. Ale dziękuję za udostępnienie.
Ich
3
Ponadto lepiej zawrzeć zakres separatora:for(let ..., sep=""; ... ; sep=",") { ...
Lawrence Dol
1
Podoba mi się to podejście, ponieważ pozwala uniknąć warunków warunkowych, chociaż nowoczesne procesory mają dobrą logikę przewidywania gałęzi. Zobacz także Dlaczego przetwarzanie posortowanej tablicy jest szybsze niż nieposortowana?
Hossein
21

Końcowe przecinki są dozwolone w JavaScript, ale nie działają w IE. Specyfikacja JSON Douglasa Crockforda bez wersji nie pozwalała na to, a ponieważ nie była wersją, nie powinno się to zmieniać. Specyfikacja ESS JSON zezwala na to jako rozszerzenie, ale RFC 4627 Crockforda nie, a ES5 powrócił do ich niedozwolenia. Firefox poszedł w ich ślady. Internet Explorer jest powodem, dla którego nie możemy mieć fajnych rzeczy.

Tobu
źródło
1
Właśnie próbowałem ich w IE 11 bez problemu. W jakich wersjach IE testowałeś, gdzie znalazłeś je, aby powodować problemy?
iconoclast
10
Wygląda na to, że Crockford nie może mieć miłych rzeczy. To i komentarze w JSON
Hejazzman
Po co wspominać o przeglądarkach internetowych, kiedy OP używało C ++ jak pseudokod? Jest mało prawdopodobne, aby pytanie OP dotyczyło przeglądarek internetowych lub JavaScript.
cowlinator
@cowlinator J Ava S CRIPT O bject N otation
forresthopkinsa
1
Literały obiektowe JavaScript zainspirowały ten format, ale JSON nie jest przeznaczony dla silników Javascript
cowlinator
13

Jak już powiedziano, specyfikacja JSON (oparta na ECMAScript 3) nie pozwala na przecinek końcowy. ES> = 5 pozwala na to, więc możesz używać tej notacji w czystym JS. Dyskutowano o tym, a niektóre parsery to poparły ( http://bolinfest.com/essays/json.html , http://whereswalden.com/2010/09/08/spidermonkey-json-change-trailing-commas- nie jest już akceptowany / ), ale faktem jest (jak pokazano na http://json.org/ ), że nie powinien on działać w JSON. Ta rzecz powiedziała ...

... Zastanawiam się, dlaczego nikt nie zauważył, że można podzielić pętlę na iteracji na 0. i użyć przecinka wiodącego zamiast końcowego, aby pozbyć się zapachu kodu porównania i rzeczywistego obciążenia wydajności w pętli, co powoduje kod, który w rzeczywistości jest krótszy, prostszy i szybszy (z powodu braku rozgałęzień / warunków w pętli) niż inne proponowane rozwiązania.

Np. (W pseudokodzie w stylu C podobnym do kodu proponowanego przez 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("]");

źródło
3
Prosty i szybki przykładowy kod. Znacznie lepsze niż rozwiązania proponowane przez inne odpowiedzi.
Trevor Jex,
12

Koderzy PHP mogą chcieć sprawdzić implode () . To zajmuje tablicę łączy ją za pomocą łańcucha.

Z dokumentów ...

$array = array('lastname', 'email', 'phone');
echo implode(",", $array); // lastname,email,phone
Rik Heywood
źródło
2
Podobnie JavaScript ma join () . Większość języków ma podobną metodę lub podobny kod można łatwo zakodować.
Dan Burton,
16
PHP ma json_encode, który obsługuje wszystkie szczegóły tworzenia JSON, nie tylko przecinki.
Brilliand
To super! W jaki sposób odnosi się do JSON i jak pomaga OP w rezolucji dotyczącej ich pytania? Pamiętaj: „Czy możesz użyć przecinka końcowego w obiekcie JSON?” jest pytanie.
Rockin4Life33
7

Co ciekawe, zarówno C, jak i C ++ (i myślę, że C #, ale nie jestem pewien) zezwalają na przecinek końcowy - właśnie z podanego powodu: znacznie ułatwia programowe generowanie list. Nie jestem pewien, dlaczego JavaScript nie poszedł w ich ślady.

James Curran
źródło
13
ECMA wyraźnie określiła, że ​​końcowe przecinki są dozwolone w nadchodzącej specyfikacji: ejohn.org/blog/bug-fixes-in-javascript-2 Kolejny powód, aby wyjaśnić, że JSON! = JS Object.
powiek
PHP też na to pozwala. Myślę, że to jedna z cech PHP, którą lubię. ; p
iconoclast
4

Użyj JSON5. Nie używaj JSON.

  • Obiekty i tablice mogą mieć przecinki końcowe
  • Klucze obiektowe mogą być niecytowane, jeśli są poprawnymi identyfikatorami
  • Ciągi znaków mogą być pojedynczymi cudzysłowami
  • Ciągi znaków można podzielić na wiele linii
  • Liczby mogą być szesnastkowe (podstawa 16)
  • Liczby mogą zaczynać się lub kończyć kropką dziesiętną (wiodącą lub końcową).
  • Liczby mogą obejmować Nieskończoność i-Nieskończoność.
  • Liczby mogą zaczynać się wyraźnym znakiem plus (+).
  • Dozwolone są zarówno komentarze wbudowane (jednowierszowe), jak i blokowe (wielowierszowe).

http://json5.org/

https://github.com/aseemk/json5

użytkownik619271
źródło
Wygląda ładnie, ale brak dodawania nowych typów danych wydaje się straconą szansą ... oczywiście pragnienie pozostania ścisłym podzbiorem ECMAScript 5 wymusza to, ale nadal ...
iconoclast
1
Również struny mutliliny są okropne. Marzę o multiliniach ES6.
Marco Sulla
10
Nie, to OGROMNA rada. Ze wszystkich istniejących bibliotek JSON bardzo niewiele obsługuje takie rozszerzenie; a wszystko to dla bardzo wątpliwych „ulepszeń”. Proszę NIE powodować dalszej erozji interoperacyjności przez takie fałszywe rozszerzenia jak ten.
StaxMan,
7
Uważam, że spędzanie życia na naprawianiu przecinków jest straszniejsze.
user619271
3

Istnieje możliwy sposób uniknięcia gałęzi if w pętli.

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
źródło
2

Zgodnie ze specyfikacją klasy JSONArray :

  • Dodatkowy (przecinek) może pojawić się tuż przed nawiasem zamykającym.
  • Wartość pusta zostanie wstawiona, gdy nastąpi (przecinek) wybór.

Tak więc, jak rozumiem, należy napisać:

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

Ale może się zdarzyć, że niektóre parsery zwrócą liczbę 7 jako liczbę przedmiotów (jak IE8, jak zauważył Daniel Earwicker) zamiast oczekiwanej liczby 6.


Edytowane:

Znalazłem ten walidator JSON, który sprawdza poprawność łańcucha JSON względem RFC 4627 (typ nośnika aplikacji / json dla notacji obiektowej JavaScript) i specyfikacji języka JavaScript. W rzeczywistości tablica z przecinkiem końcowym jest uważana za prawidłową tylko dla JavaScript, a nie dla specyfikacji RFC 4627.

Jednak w specyfikacji RFC 4627 stwierdzono, że:

2.3 Tablice

Struktura tablic jest reprezentowana przez nawiasy kwadratowe otaczające zero lub więcej wartości (lub elementów). Elementy są oddzielone przecinkami.

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

Dla mnie to znowu problem interpretacyjny. Jeśli napiszesz, że elementy są oddzielone przecinkami (nie mówiąc o specjalnych przypadkach, takich jak ostatni element), można to zrozumieć na dwa sposoby.

PS RFC 4627 nie jest standardem (jak wyraźnie zaznaczono) i jest już przestarzały w RFC 7159 (który jest proponowanym standardem) RFC 7159

Timoty Weis
źródło
6
Podana zasada gramatyki jest tak precyzyjna, jak to tylko możliwe. Nie ma sposobu, aby mieć value-separatorbez valuetuż obok niego. Również tekst jest bardzo konkretny. „Rozdzielanie wartości” można zastosować tylko wtedy, gdy istnieje wiele wartości. Więc jeśli masz dwie wartości obok siebie, są one oddzielane przecinkiem. Jeśli masz jedną wartość (lub jeśli patrzysz tylko na wartość na końcu), nie ma podziału, a więc przecinka.
Steffen Heil
1

Z moich wcześniejszych doświadczeń wynika, że ​​różne przeglądarki inaczej radzą sobie z przecinkami w JSON.

Zarówno Firefox, jak i Chrome radzą sobie dobrze. Ale IE (wszystkie wersje) wydaje się pękać. Mam na myśli naprawdę zerwanie i przestanie czytać resztę skryptu.

Mając to na uwadze, a także fakt, że zawsze miło jest pisać zgodny kod, proponuję poświęcić dodatkowy wysiłek, aby upewnić się, że nie ma przecinka końcowego.

:)

dnshio
źródło
1

Prowadzę bieżącą liczbę i porównuję ją z całkowitą liczbą. Jeśli bieżąca liczba jest mniejsza niż całkowita liczba, wyświetlam przecinek.

Może nie działać, jeśli nie masz łącznej liczby przed wykonaniem generacji JSON.

Z drugiej strony, jeśli używasz PHP 5.2.0 lub nowszego, możesz po prostu sformatować swoją odpowiedź za pomocą wbudowanego API JSON.

Eddie
źródło
1

Z Relaxed JSON możesz mieć przecinki końcowe lub po prostu je pominąć . Są opcjonalne.

Nie ma żadnego powodu, aby parsować dokument podobny do JSON.

Spójrz na specyfikację Relaxed JSON, a zobaczysz, jak „głośna” jest oryginalna specyfikacja JSON. Zbyt wiele przecinków i cytatów ...

http://www.relaxedjson.org

Możesz także wypróbować swój przykład za pomocą tego internetowego analizatora składni RJSON i zobaczyć, jak został poprawnie przeanalizowany.

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

Steven Spungin
źródło
Zrelaksowany JSON nie jest JSON, więc technicznie nie dotyczy.
user2864740,
Możesz przekonwertować rjson na i z json, więc jest to całkowicie możliwe. Bardzo łatwo dodać go również do przepływu pracy.
Steven Spungin
To powoduje założenie, że dalsi konsumenci rozumieją to nie JSON. Konwersja na prawidłowy JSON wymagałaby usunięcia przecinka w obu przypadkach.
user2864740,
OP używa łańcucha na początek. Ciąg może zostać przeanalizowany do json objectużycia JSON.parselub przez bibliotekę używającą RJSON.parse. Zgodziłbym się z tobą, gdyby źródłem był obiekt, ale tutaj tak nie jest. Nie widzę, gdzie w pytaniu w ogóle wspomina downstreamo zużyciu obiektu lub ciągu.
Steven Spungin
„Podczas ręcznego generowania obiektu lub tablicy JSON często łatwiej jest pozostawić przecinek końcowy na ostatnim elemencie w obiekcie lub tablicy. Czy jest to dozwolone [ w JSON ]?” - więc znowu: chociaż jest to interesujący alternatywny format, nie jest to JSON i technicznie nie ma zastosowania do pytania o JSON . Nie ma nic do „obrony”: to propozycja Z do pytania X.
2864740
0

Zwykle zapętlam tablicę i dołączam przecinek po każdym wpisie w ciągu. Po pętli ponownie usuwam ostatni przecinek.

Może nie najlepszy sposób, ale mniej kosztowny niż sprawdzanie za każdym razem, czy to ostatni obiekt w pętli.

Nils
źródło
0

Nie jest to zalecane, ale nadal możesz zrobić coś takiego, aby to przeanalizować.

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

feibing
źródło
0

Ponieważ pętla for służy do iteracji po tablicy lub podobnej iterowalnej strukturze danych, możemy użyć długości tablicy, jak pokazano,

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

W pliku datafile.txt zawierającym

 Angela,Baker,2010-05-23
 Betty,Crockett,1990-12-07
 David,Done,2003-10-31
Gregory Horne 07AD
źródło
0

Jak stwierdzono, nie jest to dozwolone. Ale w JavaScript jest to:

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

(działa dobrze w Firefox, Chrome, Edge, IE11 i bez let w IE9, 8, 7, 5)

theking2
źródło