为什么JSON中以0开头的整数是无效的?

72

我正在将一些JSON文件导入我的Parse.com项目中,但一直出现错误提示"无效的键值对"。

它指出有一个意外的"8"。

这是我的JSON示例:

}
 "Manufacturer":"Manufacturer",
 "Model":"THIS IS A STRING",
 "Description":"",
 "ItemNumber":"Number12345",
 "UPC":083456789012,
 "Cost":"$0.00",
 "DealerPrice":" $0.00 ",
 "MSRP":" $0.00 ",
}

如果我通过从"UPC":083456789012,中删除0或将其转换为"UPC":"083456789012",来更新JSON,则它就变得有效。

JSON真的不能接受以0开头的整数吗,还是有解决方法?


JSON语法不允许数字以数字0开头。当然,您可以将数字放在引号中。 - Pointy
以零开头的十进制数应该是一个字符串。 - Alex K.
如果你有一个0,那么很可能它不是整数而是字符标识符。只需将它们视为字符串! - Olivier Grégoire
这不是一个十进制数,而是一个UPC码,它是分配给特定产品型号的整数。@AlexK. - DJSrA
1
此外,请描述“UPC”,我们会告诉您需要一个字符串还是一个整数。 - Olivier Grégoire
它在语法上是非法的。以零开头的数字必须要么只是零,要么是一个简单的分数。请看这里:https://www.json.org/json-en.html - Mads Boyd-Madsen
6个回答

87

在JavaScript中,前导0表示一个八进制数。八进制数不能包含数字8;因此,该数字是无效的。此外,JSON并不(正式地)支持八进制数,因此即使数字不包含8,JSON也是无效的。一些解析器确实支持它,这可能会导致一些混淆。其他解析器将其识别为无效序列并抛出错误,尽管它们给出的确切解释可能不同。

解决方案:如果您有一个数字,请不要使用前导零存储它。如果您有一个需要前导零的值,请不要将其视为数字,而是将其视为字符串。用引号括起来存储它。

在这种情况下,您有一个UPC码,需要12位数字长度,可能包含前导零。我认为最好的方法是将其存储为字符串。

虽然这是有争议的。如果您将其视为条形码,将前导0视为其组成部分,则字符串是有意义的。其他类型的条形码甚至可以包含字母字符。

另一方面,UPC是一个数字,左侧用零填充到12位可以被视为显示属性。实际上,如果您通过添加额外的0将其左填到13位,则获得了EAN码,因为EAN是UPC的超集。
如果您有一个货币金额,您可能会将其显示为€ 7.30,而将其存储为7.3,因此将产品代码存储为数字也可能是有意义的。
但这个决定取决于您。我只能建议您使用字符串,这是我个人对这些代码的偏好,如果您选择数字,则必须删除0才能使其正常工作。

1
@DJSrA 问题在于前导的 0 - Pointy
3
好的,我今天确实学到了新东西。谢谢@GolezTrol。 - DJSrA
1
“leading 0”在JavaScript中表示八进制数是错误的。规范从未将前导0表示为八进制。它最初没有禁止这样做,因此一些JavaScript实现不幸地决定这样做,但它从未成为标准,现在仍然不是。在严格模式下,不允许使用八进制。在JavaScript中(截至ES2015),八进制以0o开头(大小写不敏感,类似于十六进制的0x)。 - T.J. Crowder
2
@T.J.Crowder 说得好。它是一个可选的扩展,因此在标准中提到了它,但这只是语义学问题。它确实一直被反对,目前已经被禁止在标准中使用,因此最好避免在 Json 和 JavaScript 中使用八进制数。 - GolezTrol
2
@GolezTrol:哇,你说得完全正确。我回去检查了一下,ECMAScript规范的第一版和第二版都列出了OctalIntegerLiteral,没有任何明显的犹豫。我的错!第三版已经弃用它,第五版引入了严格模式来删除它。 - T.J. Crowder
显示剩余5条评论

11

JavaScript中比较令人困惑的一部分是,如果一个数字以0开头且后面没有紧跟着.,它代表的是八进制而不是十进制。

JSON借用了JavaScript语法,但避免了混淆的特性,因此直接禁止具有前导零的数字(除非它们后面跟着一个.)。

即使不是这种情况,也没有理由预期当数字被解析时0仍然在其中,因为022只是相同数字的不同表示(如果你强制使用十进制)。

如果前导零对于您的数据很重要,那么您可能有一个字符串而不是数字。

"UPC":"083456789012"

一个产品代码是一个标识符,不是你用来进行数学运算的东西。它应该是一个字符串。


感谢您的迅速回答。 - DJSrA

3

形式上,这是因为 JSON 在其 JSONNumber 生成中使用了 DecimalIntegerLiteral

JSONNumber ::
    -_opt DecimalIntegerLiteral JSONFraction_opt ExponentPart_opt

如果是DecimalIntegerLiteral,只有当它为0时才可以以0开头:

DecimalIntegerLiteral ::
    0
    NonZeroDigit DecimalDigits_opt

这背后的理由可能是:
  • 在 JSON 语法中,重用主要的 ECMAScript 语法结构。
  • 在主要的 ECMAScript 语法中,更容易区分 DecimalIntegerLiteralHexIntegerLiteralOctalIntegerLiteral。首先需要区分 OctalIntegerLiteral
请看以下表述:
 HexIntegerLiteral ::
     0x HexDigit
     0X HexDigit
    HexIntegerLiteral HexDigit

...

OctalIntegerLiteral ::
    0 OctalDigit
    OctalIntegerLiteral OctalDigit

2
如果DecimalIntegerLiteral以0开头,则只有在其后紧跟着小数点和更多数字时,它才可以以0开头。 - CupawnTae
3
这不是“DecimalIntegerLiteral”。 - lexicore
1
@lexicore 哦,没错,JSONFraction_opt 处理了那一部分。我读得太快了,抱歉 :) - CupawnTae

2
UPC应该以字符串格式呈现。将来,您可能还会获得其他类型的UPC,例如GS128或基于字符串的产品识别码。请将您的数据库列设置为字符串。

0
我认为以JSON的方式发送您的数字最简单的方法是将您的数字发送为字符串。

这不是八进制 - 它是一个固定长度的代码,应该被视为字符串处理。 - CupawnTae

0

如果在JavaScript中一个整数以0开头,它将被视为该整数的八进制(基数为8)值,而不是十进制(基数为10)值。例如:

var a = 065; //Octal Value
var b = 53;  //Decimal Value
a == b; //true

1
除非在JSON中完全无效...尝试JSON.parse("65")JSON.parse("065") - CupawnTae
也许,只有当有人感到困惑时:065 => 08^2 + 68^1 + 5*8^0 = 53(十进制) - RedRose

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接