如何在 Node.js 中解析包含“NaN”的 JSON 字符串

Posted

技术标签:

【中文标题】如何在 Node.js 中解析包含“NaN”的 JSON 字符串【英文标题】:How to parse JSON string containing "NaN" in Node.js 【发布时间】:2013-02-20 03:22:08 【问题描述】:

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

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

这会使 Node.js 中的 JSON.parse(...) 崩溃。我想把它解析成一个对象。

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

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

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

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

JSON 规范的第 2.4 节不允许特殊的双精度值 (NaN,无穷大,-无穷大)。然而,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: How to encode infinity or NaN numbers to JSON?

【问题讨论】:

我觉得讽刺的是,Google 的 Gson 项目说 JSON 解析器应该允许这些文字,而不能容忍它们的 JavaScript 引擎是 Google 自己的 V8。 @cdhowie 节点的 JSON 解析器只是遵循规范。 “讽刺”只是违反the robustness principle. @MattBall 不,具有讽刺意味的是,一个 Google 项目说 “大多数 JavaScript 引擎将毫无问题地接受 JSON 中的这些特殊值”,而 Google 的 JavaScript 引擎是其中之一Chrome 也不喜欢该字符串这一事实证明了例外情况。 “第 1.2 节描述了 JSON。但是,TCP/IP 协议支持许多其他格式,只要付出足够的努力或无视安全性,您应该能够解码。因此,我们想,为什么要限制自己使用 JSON? " - 谷歌 【参考方案1】:

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

那么您的 NodeJS 应用程序没有接收JSON,它接收的文本有点类似于 JSON。 NaN 不是有效的 JSON 令牌。

三个选项:

1。获取源以正确生成 JSON

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

2。以朴素的方式容忍NaN

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

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

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

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

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 允许任意执行代码,因此如果字符串有任何被篡改的可能性,请不要使用它。

【讨论】:

假设文本“NaN”从未出现在字符串中。要做到这一点 The Right Way(TM) 需要解析 JSON 以确定无效标记的位置——此时您不妨将解析树转换为对象。所以基本上,正确的解决方案是编写你自己的 NaN 容错 JSON 解析器。 哇!我正准备为未能找到一个有据可查的选择而感到羞耻。因此,从好的方面来说,似乎找不到该选项。 @user645715:哈哈 确实不是。 :-) 很高兴有帮助! 非常周到的回复。字符串替换现在有效。但是数据文件是多种多样的任意和用户提供的,所以很可能在文本列中包含“NaN”,并且对 eval() 的关注也是有效的。看看我是否可以改变图书馆本身。谢谢! 我选择了选项 3,值得一提的是,您需要在输入中添加括号:function myParseJSON(almost_json) return eval("(" + almost_json + ")") 【参考方案2】:

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

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

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

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

这就是我编写特定解析器(用于生产)的原因:JSON.parseMore

【讨论】:

这很棒。在大字符串中添加括号也会在 Node.js 中使用大量内存,这可以避免这种情况。【参考方案3】:

您可以使用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】:

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

优秀的 JSON 库将允许解析几乎任何与 JSON 模糊相似且设置了正确标志的内容(perl 的 JSON.pm 非常灵活)......但是在编写消息时,它们会生成标准 JSON。

IE:让房间比你找到时更干净。

【讨论】:

【参考方案5】:

只是对 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"'))

【讨论】:

以上是关于如何在 Node.js 中解析包含“NaN”的 JSON 字符串的主要内容,如果未能解决你的问题,请参考以下文章

为啥 + 仅在客户端是 NaN?为啥不在 Node.js 中?

Node.js DNS 响应延迟

错误:找不到模块“nan”

在 Node JS 中解析包含单个对象的数组

使用 Node.js 解析不包含 JSON 对象的 JSON 数组

如何使用 Node.js 解析 HTML/XML 文档?