您可以在 JSON 对象中使用尾随逗号吗?

Posted

技术标签:

【中文标题】您可以在 JSON 对象中使用尾随逗号吗?【英文标题】:Can you use a trailing comma in a JSON object? 【发布时间】:2010-09-17 03:18:16 【问题描述】:

手动生成 JSON 对象或数组时,在对象或数组的最后一项上留下逗号通常更容易。例如,从字符串数组输出的代码可能看起来像(在类似 C++ 的伪代码中):

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

s.append("]");

给你一个类似的字符串

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

这是否允许?

【问题讨论】:

这是我几天前需要在网上查找的内容。我在 SO 上没有看到答案,所以在遵循该网站的使命时,我提出了问题并回答了它,以便其他人可以找到它。这是杰夫明确表示他想在这里完成的事情。 正如 Jeff 所说,我认为将 SO 用作您必须花一些时间查找的东西的“笔记本”非常好。当然,这只是这些类型项目的简单结束,但我仍然认为它是合适的,特别是因为不同的 javascript 引擎会以不同的方式处理这一点。 我也想知道这个问题,所以这是一个完全合理的问题。 在 IE 8 中有趣(或可怕)我刚刚发现 alert([1, 2, 3, ].length) 将显示“4”。 同意这是一个很好的问题。我是通过谷歌搜索到这里的。 【参考方案1】:

很遗憾,the JSON specification 不允许结尾有逗号。有一些浏览器允许它,但通常您需要担心所有浏览器。

一般来说,我会尝试解决问题,并在实际值之前添加逗号,因此您最终会得到如下所示的代码:

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

在你的 for 循环中多出一行代码并不昂贵...

当从某种形式的字典向 JSON 输出结构时,我使用的另一种替代方法是始终在每个条目之后附加一个逗号(如您在上面所做的那样),然后在末尾添加一个没有尾随的虚拟条目逗号(但这只是懒惰;->)。

不幸的是,它不适用于数组。

【讨论】:

正是出于这个原因,我已经开始在我的所有 JS 代码中使用这种格式(同一行项目前的逗号)。使额外的尾随逗号更容易发现,并节省大量时间。这很烦人,我希望有一个选项可以用 Firefox 抛出错误(因为这有助于调试)。 ECMA5 指定尾随,但 JSON 没有。 是的,那条额外的线路并不贵,但还是很麻烦。 这种方法适用于索引 for 循环。 for...in 样式循环怎么样?有没有优雅的方法? 额外的一行代码在处理属性时可能会很复杂。您可能会发现自己拥有大量的ifs 只是为了避免那个愚蠢的小逗号。关于昂贵的 YMMV,请参阅此示例 jsfiddle.net/oriadam/mywL9384 澄清:您的解决方案很棒,我只是讨厌禁止尾随逗号的规范。【参考方案2】:

没有。在 http://json.org 维护的 JSON 规范不允许尾随逗号。据我所见,一些解析器在读取 JSON 字符串时可能会默默地允许它们,而其他解析器会抛出错误。为了互操作性,您不应包含它。

上面的代码可以重构,要么在添加数组终止符时删除尾随逗号,要么在项目前添加逗号,为第一个跳过逗号。

【讨论】:

ECMA 262 似乎在 11.1.5-Object Initialiser 小节中有定义。无论这是否好,似乎都在规范中。 有效的 ECMAScript 并不一定意味着文档是有效的 JSON - JSON 通常在 RFC 4627 中定义,并且该规范不允许尾随逗号。 @ZeroDistraction:ECMA262 定义了 ECMAscript(也称为 javascript),它是一种类似于 Perl、Ruby、C++ 或 Java 的编程语言。 JSON 是一种数据格式,如 XML、CSV 或 YAML。它们不是同一件事。 JSON 在 EXMA262 中不存在,但它派生的语法确实存在,它被称为对象文字表示法(JSON 中的 ON)。【参考方案3】:

简单、便宜、易于阅读,并且无论规格如何都始终有效。

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

对 $delim 的冗余分配是一个很小的代价。 如果没有显式循环而是单独的代码片段,也同样有效。

【讨论】:

在这种情况下我通常会这样做;我觉得通过消除在替代方法 (***.com/a/201856/8946) 中的值之前附加逗号所需的条件来抵消额外的分配。 我不喜欢这个解决方案,因为有另一个变量污染了我的范围。一个if 更容易掌握。不过谢谢分享。 另外,最好包含分隔符的范围:for(let ..., sep=""; ... ; sep=",") ... 我喜欢这种方法,因为它避免了条件,尽管现代 CPU 具有良好的分支预测逻辑。另请参阅Why is it faster to process a sorted array than an unsorted array?【参考方案4】:

在 JavaScript 中允许使用尾随逗号,但在 IE 中不能使用。 Douglas Crockford 的无版本 JSON 规范不允许它们,因为它是无版本的,所以不应该改变。 ES5 JSON 规范允许它们作为扩展,但 Crockford 的 RFC 4627 没有,ES5 恢复为不允许它们。 Firefox 紧随其后。 Internet Explorer 是我们无法拥有美好事物的原因。

【讨论】:

我刚刚在 IE 11 中尝试过没有问题。您在哪些版本的 IE 中进行了测试,您发现它们在哪里导致问题? 似乎 Crockford 是我们无法拥有美好事物的原因。 JSON 中的那个和 cmets 当 OP 像伪代码一样使用 C++ 时,为什么要提到 Web 浏览器? OP 的问题不太可能与网络浏览器或 JavaScript 有关。 @cowlinator JavaScript Object Notation Javascript 对象文字启发了这种格式,但 JSON 不适用于 Javascript 引擎【参考方案5】:

如前所述,JSON 规范(基于 ECMAScript 3)不允许尾随逗号。 ES >= 5 允许它,因此您实际上可以在纯 JS 中使用该符号。有人争论过,一些解析器确实支持它(http://bolinfest.com/essays/json.html,http://whereswalden.com/2010/09/08/spidermonkey-json-change-trailing-commas-no-longer-accepted/),但它是规范事实(如http://json.org/所示)它不应该 在 JSON 中工作。那件事说...

...我想知道为什么没有人指出您实际上可以在第 0 次迭代时拆分循环并使用 leading 逗号而不是尾随一个逗号来消除比较代码的气味和循环中的任何实际性能开销,导致代码实际上比其他建议的解决方案更短、更简单和更快(由于循环中没有分支/条件)。

例如(在类似于 OP 提议的代码的 C 风格伪代码中):

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

【讨论】:

简单快速的代码示例。比其他答案提出的解决方案要好得多。【参考方案6】:

php 编码人员可能想查看 implode()。这需要一个数组使用字符串将其连接起来。

来自docs...

$array = array('lastname', 'email', 'phone');
echo implode(",", $array); // lastname,email,phone

【讨论】:

同样,JavaScript 有join()。大多数语言都有类似的方法,或者类似的方法可以很容易地编码。 PHP 有 json_encode,它处理制作 JSON 的所有细节,而不仅仅是逗号。 太酷了!它如何应用于 JSON 以及它如何帮助 OP 解决他们的问题?请记住,“您可以在 JSON 对象中使用尾随逗号吗?”是问题。 python 已加入:','.join(mylist)【参考方案7】:

有趣的是,C 和 C++(我认为是 C#,但我不确定)都特别允许尾随逗号 - 正是因为给出的原因:它使以编程方式生成列表变得更加容易。不知道为什么 JavaScript 没有跟随他们的领导。

【讨论】:

ECMA 已明确规定在即将发布的规范中允许使用尾随逗号:ejohn.org/blog/bug-fixes-in-javascript-2 另一个需要明确的原因是 JSON != JS Object。 PHP 也允许这样做。我认为这是我喜欢的 PHP 的一个特性。 ;p【参考方案8】:

使用 JSON5。不要使用 JSON。

对象和数组可以有尾随逗号 如果对象键是有效标识符,则可以不加引号 字符串可以单引号 字符串可以分成多行 数字可以是十六进制(以 16 为基数) 数字可以以(前导或尾随)小数点开始或结束。 数字可以包括 Infinity 和 -Infinity。 数字可以以明确的加号 (+) 开头。 允许内联(单行)和块(多行)cmets。

http://json5.org/

https://github.com/aseemk/json5

【讨论】:

看起来不错,但不添加新数据类型似乎是一个错失的机会……当然,保持 ECMAScript 5 严格子集的愿望迫使这一点,但仍然…… 另外,多行字符串也很糟糕。我梦想着 ES6 多行。 不,这是可怕的建议。在所有现有的 JSON 库中,很少有人支持这种扩展;而这一切都是为了非常有问题的“改进”。请不要通过像这样的新虚假扩展进一步削弱互操作性。 我认为把你的一生都花在修正逗号上更可怕。【参考方案9】:

与其参加辩论俱乐部,我会申请Defensive Programming,并利用这两种技术:

作为接收 json 数据的应用程序的开发者,我会放松允许尾随逗号。

在开发 编写 json 的应用程序时,我会 strict 并使用其他答案的巧妙技术之一,仅在项目和 之间添加逗号>避免尾随逗号。

还有更大的问题需要解决……

【讨论】:

这被称为 Postel 规则:en.wikipedia.org/wiki/Robustness_principle 不幸的是,这是一个非常糟糕的主意。您应该准确地执行规范并大声拒绝所有不合格的输入。稳健性原则导致数十种实现都在做微妙的不同事情,导致咬牙切齿。有多种输入方式超出规范;没有两个实现者会以完全相同的方式进行扩展。用户将针对一种实现准备他们的数据,然后不让它在另一种实现中工作。 这就是***页面的批评部分的内容。 @Kaz 你当然有道理。但我是因为开发工作应用程序而获得报酬,而不是因为应用程序停止并抱怨输入错误的错误消息。坏的?以 HTML 为例。如果浏览器很严格,大多数网站都会停止工作。哎呀,现在我被引诱到辩论中。 . . HTML 正是这方面的典型例子。如果浏览器从一开始就很严格,而不是为了渲染损坏的 HTML 而竞争,那么 Web 标准会更好。您的前端代码不必处理不同浏览器的七种情况,您必须通过艰苦的经验来解决。【参考方案10】:

有一种方法可以避免循环中出现 if 分支。

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

【讨论】:

【参考方案11】:

没有。 https://json.org 中的“铁路图”是对规范的精确翻译,并清楚地表明 , 总是出现在 value 之前,而不是直接出现在 ] 之前:

:

【讨论】:

【参考方案12】:

根据Class JSONArray specification:

一个额外的 ,(逗号)可能出现在右括号之前。 当有 ,(逗号)省略时,将插入空值。

所以,据我了解,应该允许写:

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

但某些解析器可能会返回 7 作为项目计数(如 Daniel Earwicker 指出的 IE8)而不是预期的 6。


已编辑:

我发现了这个JSON Validator,它根据RFC 4627(JavaScript 对象表示法的应用程序/json 媒体类型)和 JavaScript 语言规范验证 JSON 字符串。实际上,此处带有尾随逗号的数组仅对 JavaScript 有效,而对 RFC 4627 规范无效。

然而,在 RFC 4627 规范中声明:

2.3。数组

数组结构表示为围绕零的方括号 或更多值(或元素)。元素用逗号分隔。

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

对我来说,这又是一个解释问题。如果你写元素用逗号分隔(没有说明一些特殊情况,比如最后一个元素),它可以从两个方面理解。

附: RFC 4627 不是标准(如明确说明的那样),并且已被 RFC 7159(建议的标准)RFC 7159

废弃

【讨论】:

给出的语法规则尽可能精确。没有value-separator 旁边没有value,就不可能有value-separator。文字也很具体。 “值分离”仅适用于存在多个值的情况。因此,如果您有两个相邻的值,它们将使用逗号分隔。如果您有一个值(或者如果您只查看最后的值),则没有分隔,因此没有逗号。 您的样本包含 7 个元素,6 个类型的整数一个 void。不要将其视为“尾随”,而更多地视为允许为空或不为空的表达式。来自解析器构建的历史,这确实是这里的问题 [0, , , ] 中有多少元素?一个还是四个?【参考方案13】:

使用宽松 JSON,您可以使用尾随逗号,或不使用逗号。它们是可选的。

完全没有理由需要使用逗号来解析类似 JSON 的文档。

看看Relaxed JSON 规范,您会发现原始JSON 规范是多么的“嘈杂”。太多的逗号和引号......

http://www.relaxedjson.org

您还可以使用此在线 RJSON 解析器尝试您的示例,并查看它是否被正确解析。

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

【讨论】:

宽松的 JSON 不是 JSON,所以技术上不适用。 您可以将rjson与json相互转换,因此完全适用。也很容易将其添加到您的工作流程中。 这假设下游消费者理解这个非 JSON。在任何一种情况下,转换为有效的 JSON 都需要删除逗号。 OP 使用字符串开头。该字符串可以使用JSON.parse 解析为json object,或者由使用RJSON.parse 的库解析。如果源是一个对象,我会同意你的看法,但这里不是这样。我看不到它在问题中提到downstream 的位置完全消耗了一个对象或字符串。 "当手动生成 JSON 对象或数组时,在对象或数组的最后一项上留下逗号通常更容易。这是否允许 [在 JSON 中]?” - 所以,再说一遍:虽然这是一种有趣的替代格式,但它不是不是 JSON,并且在技术上不适用于关于 JSON 的问题。没有什么可以“捍卫”的:这是一个 Z 的提议来质疑 X。【参考方案14】:

如上所述,这是不允许的。但在 JavaScript 中是这样的:

var a = Array()
for(let i=1; i<=5; i++) 
    a.push(i)

var s = "[" + a.join(",") + "]"

(在 Firefox、Chrome、Edge、IE11 中运行良好,并且在 IE9、8、7、5 中没有 let)

【讨论】:

【参考方案15】:

根据我过去的经验,我发现不同的浏览器以不同的方式处理 JSON 中的尾随逗号。

Firefox 和 Chrome 都能很好地处理它。但 IE(所有版本)似乎坏了。我的意思是真的打破并停止阅读脚本的其余部分。

记住这一点,以及编写合规代码总是很好的事实,我建议花额外的精力确保没有尾随逗号。

:)

【讨论】:

【参考方案16】:

我保留当前计数并将其与总计数进行比较。如果当前计数小于总计数,则显示逗号。

如果您在执行 JSON 生成之前没有总计数,则可能无法工作。

再一次,如果您使用 PHP 5.2.0 或更高版本,您可以使用内置的 JSON API 格式化您的响应。

【讨论】:

【参考方案17】:

不推荐,但你仍然可以这样做来解析它。

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

【讨论】:

【参考方案18】:

由于使用for循环来迭代数组或类似的可迭代数据结构,我们可以使用数组的长度,如图所示,

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

含datafile.txt,

 Angela,Baker,2010-05-23
 Betty,Crockett,1990-12-07
 David,Done,2003-10-31

【讨论】:

【参考方案19】:

我通常遍历数组并在字符串中的每个条目后附加一个逗号。在循环之后,我再次删除最后一个逗号。

也许不是最好的方法,但比每次检查它是否是循环中的最后一个对象要便宜。

【讨论】:

以上是关于您可以在 JSON 对象中使用尾随逗号吗?的主要内容,如果未能解决你的问题,请参考以下文章

数组和对象中的尾随逗号是规范的一部分吗?

数组和对象中的尾随逗号是规范的一部分吗?

我应该在函数调用中的最后一个参数后添加一个尾随逗号吗?

x, = ... - 这个尾随逗号是逗号运算符吗?

python字典自动添加尾随逗号

tslint - 最后一行缺少尾随逗号(尾随逗号)