30

有一个 node.js 应用程序正在接收包含文字 NaN 的 JSON 数据字符串,例如

 "[1, 2, 3, NaN, 5, 6]"

JSON.parse(...)这在 Node.js 中崩溃。如果可以的话,我想将其解析为一个对象。

我知道NaN不是 JSON 规范的一部分。大多数 SO 链接(在 json 中发送 NaN)建议修复输出。

在这里,虽然数据是在我无法控制的服务器中生成的,但它是由一个商业 Java 库生成的,我可以在其中看到源代码。它由 Google 的 Gson 库生成:

private Gson gson = (new GsonBuilder().serializeSpecialFloatingPointValues().create()); 
... 
gson.toJson(data[i], Vector.class, jsonOut)

所以这似乎是一个合法的来源。根据Gson API Javadoc,它说我应该能够解析它:

JSON 规范的第 2.4 节不允许特殊的双精度值(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作为文字的替代解析器?

我已经在谷歌上搜索了一段时间,但似乎找不到关于这个问题的文档。

PHP:如何将无穷大或 NaN 数字编码为 JSON?

4

5 回答 5

51

有一个 node.js 应用程序正在接收包含文字 NaN 的 JSON 数据字符串,例如

然后你的 NodeJS 应用程序没有接收JSON,它接收到的文本有点类似于 JSON。NaN不是有效的 JSON 令牌。

三个选项:

1.获取源正确生成JSON

这显然是首选课程。数据不是 JSON,应该修复,这将解决您的问题。

NaN2.以简单的方式容忍:

null您可以在解析之前将其替换为,例如:

var result = JSON.parse(yourString.replace(/\bNaN\b/g, "null"));

...然后null在结果中处理 s 。但这很简单,它不允许字符NaN出现在某个字符串中的可能性。

或者,旋转 Matt Ball 的reviver想法(现已删除),您可以将其更改为特殊字符串(如"***NaN***"),然后使用 reviver 将其替换为 real NaN

var result = JSON.parse(yourString.replace(/\bNaN\b/g, '"***NaN***"'), function(key, value) {
    return value === "***NaN***" ? NaN : value;
});

...但是假设角色NaN从未出现在适当的位置,那么这同样具有头脑简单的问题。

3.使用(颤抖!) eval

如果您知道并信任此数据的来源,并且在传输过程中不可能被篡改,那么您可以使用eval来解析它而不是JSON.parse. 由于eval允许完整的 JavaScript 语法,包括NaN,它有效。希望我的警告足够大胆,让人们明白我只会在少数情况下推荐这个。但同样,请记住eval允许任意执行代码,因此如果字符串有任何被篡改的可能性,请不要使用它。

于 2013-03-05T16:13:18.163 回答
6

当您处理任何数学或行业数据时,NaN它非常方便(通常也是无穷大)。它是自 IEEE754 以来的行业标准。

这显然是为什么一些库,尤其是 GSON,允许您将它们包含在它们生成的 JSON 中,从而失去标准纯度并获得理智。

当您交换复杂的动态对象时,Revival 和正则表达式解决方案在实际项目中无法可靠使用。

并且eval也有问题,其中一个是当 JSON 字符串很大时它很容易在 IE 上崩溃,另一个是安全风险。

这就是为什么我编写了一个特定的解析器(用于生产):JSON.parseMore

于 2014-04-25T06:51:35.160 回答
5

您可以使用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]
于 2018-11-07T09:59:53.883 回答
0

正确的解决方案是重新编译解析器,并为源代码库贡献一个“allowNan”布尔标志。这是其他库的解决方案(想到了python)。

好的 JSON 库将允许解析几乎任何与 JSON 类似且带有正确标志的东西(perl 的 JSON.pm 非常灵活)......但是在编写消息时,它们会生成标准 JSON。

IE:让房间比你发现的更干净。

于 2015-03-11T19:36:41.640 回答
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"'))
}
于 2021-08-10T14:56:14.330 回答