有一个node.js应用程序正在接收包含文字NaN的JSON数据字符串,例如
"[1, 2, 3, NaN, 5, 6]"
这会在Node.js中崩溃JSON.parse(...)
。如果我可以进入一个物体,我想解析它。
我知道NaN
不是JSON规范的一部分。大多数SO链接(sending NaN in json)建议修复输出。
这里,尽管数据是在我无法控制的服务器中生成的,但它是由商业Java库提供的,我可以看到源代码。它由谷歌的Gson图书馆制作:
private Gson gson = (new GsonBuilder().serializeSpecialFloatingPointValues().create());
...
gson.toJson(data[i], Vector.class, jsonOut)
所以这似乎是一个合法的来源。根据{{3}}它说我应该能够解析它:
JSON规范的第2.4节不允许使用特殊的double值 (NaN,Infinity,-Infinity)。但是,Javascript规范(参见 第4.3.20,4.3.22,4.3.23节允许这些值有效 Javascript值。而且,大多数JavaScript引擎都会接受这些 JSON中的特殊值没有问题。所以,在实际层面上,它 有意义的是接受这些值作为有效的JSON,即使JSON 规范不允许它们。
尽管如此,Node.js和Chrome都失败了:JSON.parse('[1,2,3,NaN,"5"]')
JSON.parse()中是否有要设置的标志?或者是一个接受NaN
作为文字的替代解析器?
我一直在谷歌搜索一段时间,但似乎无法找到关于这个问题的文档。
答案 0 :(得分:31)
有一个node.js应用程序正在接收包含文字NaN的JSON数据字符串,例如
然后你的NodeJS应用不接收JSON,它正在接收类似JSON的文字。 NaN
不是有效的JSON令牌。
三个选项:
这显然是首选课程。数据不是JSON,应修复,这将解决您的问题。
NaN
:在解析之前,您可以用null
替换它,例如:
var result = JSON.parse(yourString.replace(/\bNaN\b/g, "null"));
...然后在结果中处理null
个。但这很简单,它不允许字符NaN
出现在字符串中的可能性。
或者,旋转Matt Ball的reviver
想法(现已删除),您可以将其更改为特殊字符串(如"***NaN***"
),然后使用reviver替换真实的NaN
:
var result = JSON.parse(yourString.replace(/\bNaN\b/g, '"***NaN***"'), function(key, value) {
return value === "***NaN***" ? NaN : value;
});
...但是,假设字符NaN
永远不会出现在适当的位置,那就有点同样简单的问题。
eval
如果您了解并信任此数据的来源并且没有可能在运输途中被篡改 ,那么您可以使用eval
进行解析而不是JSON.parse
。由于eval
允许使用完整的JavaScript语法,包括NaN
,因此有效。希望我能够让人们明白我只会在一个非常非常非常微小百分比的情况下推荐它。但同样,请记住eval
允许任意执行代码,因此如果字符串被篡改的可能性,请不要使用它。
答案 1 :(得分:4)
当您处理任何数学或行业数据时,NaN
非常方便(通常也是无限的)。它是IEEE754以来的行业标准。
这显然是为什么有些图书馆,特别是GSON,允许你将它们包含在他们制作的JSON中,失去标准的纯度并获得理智。
当您交换复杂的动态对象时,复兴和正则表达式解决方案在实际项目中无法可靠地使用。
eval
也存在问题,其中一个问题是,当JSON字符串很大时,它很容易在IE上崩溃,另一个是安全风险。
这就是为什么我写了一个特定的解析器(用于制作):JSON.parseMore
答案 2 :(得分:0)
正确的解决方案是重新编译解析器,并向源基础提供“allowNan”布尔标志。这是其他图书馆的解决方案(想到了python)。
好的JSON库将允许解析任何与JSON相似的东西,并设置正确的标志(perl的JSON.pm非常灵活)......但是在编写消息时,他们会生成标准的JSON。
IE:让房间比你找到的更干净。
答案 3 :(得分:0)
您可以使用JSON5库。项目页面中的报价:
JSON5数据交换格式(JSON5)是JSON的超集,旨在通过扩展其语法以包含ECMAScript 5.1的某些产品来减轻JSON的某些局限性。
此JavaScript库是JSON5解析和序列化库的官方参考实现。
如您所料,它确实支持解析NaN(与Python等类似的序列化方式兼容):
JSON5.parse("[1, 2, 3, NaN, 5, 6]")
> (6) [1, 2, 3, NaN, 5, 6]
答案 4 :(得分:0)
只是对 TJ Crowder 已经足够全面的回复的一个小补充,我宁愿使用
var result = JSON.parse(yourString.replace(/\bNaN\b/g, '"NaN"'));
因为我实际上需要知道它是否是 NaN 值。
此外,我会在 fetch 或 axios GET 请求中执行此操作,前提是默认 JSON 解析失败并且数据以字符串形式出现。
const StringConstructor = "".constructor;
if (data.constructor === StringConstructor) {
data = JSON.parse(tableData.data.replace(/\bNaN\b/g, '"NaN"'))
}