JSON(JavaScript? 对象表示法)是一种基于 JavaScript? 数据结构格式的数据序列化格式。有关 JSON 的一般信息,请参阅 https://json.js.cn/ 和 [JSON 的维基百科文章]。
JSON 模块比较
由于一些模块仅称为“json”,因此添加了首字母以创建唯一名称
- cmj-JSON4Lua (版本 0.9.5)
- dkjson (版本 2.1)
- Fleece (版本 0.3.1)
- jf-JSON (版本 20160526.15)
- Lua-Yajl (版本 2.0)
- mp-CJSON / Lua CJSON (版本 1.0.2)
- sb-Json (2007 年版本)
- th-LuaJSON (版本 1.2.1)
- luci.json (版本 0.11+)
- lunajson (版本 1.1) (由作者单独测试)
此比较最初由 dkjson 的作者 DavidKolf 发起,因此可能存在偏见。
为了进行比较,使用了默认选项。我(DavidKolf)期望模块在默认设置下符合 JSON 标准。Fleece 是一个例外,此比较中的大多数内容对于“E4”选项以外的选项都没有意义。
dkjson 仓库中可以找到 [功能/合规性测试] 和 [速度测试]。
进一步的 JSON 实现
此比较(尚未)包含的 JSON 实现
主要错误
- Fleece:
- 编码 +/-math.huge (Infinity) 会导致程序冻结(无限循环)。
- 编码大于或等于 128 的 UTF-8 代码点会取消后续输出。
- 引用循环会导致分段错误。
编码时的转义字符
根据 [RFC 4627],0 到 31 范围内的所有字符以及 \\ 和 \" 都必须转义。但是,建议也转义 Unicode 字符 U+2028 和 U+2029,以便 [生成有效的 JavaScript]。 [原始 JSON 实现] 甚至更进一步,转义了 BMP 中的大多数控制字符和未定义的代码点。
- cmj-JSON4Lua:\\、\"、\n、\t,以及 \'(这不是有效的 JSON 转义码)。包含此字符的 JSON 文件将无法在原始实现中加载。
- dkjson:0 到 31 范围内的所有字符,\\、\"、127 以及原始实现转义的其他 Unicode 控制字符。
- Fleece(使用 E4 选项):0 到 31 范围内的所有字符,\\、\"、\ /、127。127 以上的所有字符都会取消后续输出。
- jf-JSON:0 到 31 范围内的所有字符,\\、\"。可选地也转义 U+2028 和 U+2029。
- Lua-Yajl:0 到 31 范围内的所有字符,\\、\"。
- mp-CJSON:0 到 31 范围内的所有字符,\\、\"、\ /、127。
- sb-Json:0 到 31 范围内的所有字符,\\、\"、\ /、127。
- th-LuaJSON:0 到 31 范围内的所有字符,\\、\"、\ /。 \u000b (11) 被转义为 \v,这不是有效的 JSON 代码,并且无法在原始实现中加载。
- lunajson:0 到 31 范围内的所有字符,\\、\"。
解码时支持 Unicode 转义序列 \uXXXX
- cmj-JSON4Lua:不支持
- dkjson:完全支持 0 到 0x10ffff,正确地将 [UTF-16] 代理对转换为 [UTF-8]。
- jf-JSON:完全支持 0 到 0x10ffff,正确地将 UTF-16 代理对转换为 UTF-8。
- Lua-Yajl:完全支持 0 到 0x10ffff,正确地将 UTF-16 代理对转换为 UTF-8。
- mp-CJSON:完全支持 0 到 0x10ffff,正确地将 UTF-16 代理对转换为 UTF-8。
- sb-Json:支持 0 到 0xff 范围,创建 8 位编码(latin1 或类似)。
- th-LuaJSON:支持 0 到 0xffff 范围,但不转换 UTF-16 代理对,因此 0x10000 到 0x10ffff 会被编码为 [CESU-8] 而不是 UTF-8。
- lunajson:完全支持 0 到 0x10ffff,正确地将 UTF-16 代理对转换为 UTF-8。
其他错误
- cmj-JSON4Lua:
- 解码空数组会引发错误。
- 解码指数部分带有加号的数字会引发错误(“1e+2”)。
编码的边缘情况
JSON 无法表示所有 Lua 结构。本节列出了一些情况下的行为。您不应将此类数据馈送到任何 JSON 模块,但了解模块如何处理这些数据仍然很有趣。模块不应挂起或崩溃,并且不应产生无效的 JSON 输出(引发 Lua 错误是处理此类数据的有效方式)。
混合表
{[1] = 1, a = 2}
稀疏数组
{[1000] = "test"}
- cmj-JSON4Lua:编码为大数组。
- dkjson:编码为带字符串键的对象。
- Fleece:编码为带整数键的对象(无效 JSON)。
- jf-JSON:编码为大数组。
- Lua-Yajl:编码为大数组。
- mp-CJSON:对过稀的数组引发错误,并将其他稀疏数组转换为带字符串键的对象。行为可以通过运行时配置。
- sb-Json:编码为大数组。
- th-LuaJSON:编码为带字符串键的对象。
- luci.json:编码为带字符串键的对象。
- lunajson:除非明确指定数组长度,否则会引发错误(数组长度由索引 0 指定,例如 {[0] = 1000, [1000] = "test"})。
NaN 和 Inf 的处理
nan = math.huge * 0
inf = math.huge
- cmj-JSON4Lua:原始 tostring() 输出(无效 JSON)。
- dkjson:“null”(类似于原始 JSON 实现)。
- Fleece:NaN 是 0.0000,对 +/-Inf 冻结。
- jf-JSON:NaN 是“null”,Inf 是 1e+9999。
- Lua-Yajl:NaN 是 -0,Inf 是 1e+666。
- mp-CJSON:默认引发无效 JSON 错误,但可以通过运行时配置(“null”或 NaN/Inf)。
- sb-Json:原始 tostring() 输出(无效 JSON)。
- th-LuaJSON:JavaScript? 常量:NaN 是 'NaN',Inf 是 'Infinity'(这是有效的 JavaScript?,但无效 JSON)。
- luci.json:NaN 是 nan,inf 是 inf。
- lunajson:引发错误(无效数字)。
编码时防止引用循环
a = {}
a.a = a
- cmj-JSON4Lua:否,无限循环。
- dkjson:是,引发错误。
- Fleece:否,分段错误。
- jf-JSON:是,引发错误。
- Lua-Yajl:是,引发错误。
- mp-CJSON:是,引发错误。限制可以通过运行时配置。
- sb-Json:否,无限循环。
- th-LuaJSON:是,引发错误。
- luci.json:是,返回 nil,但需要“一段时间”才能完成(CPU 占用率高)。
- lunajson:是,引发错误。
空数组的处理
local json_str = '{"items":[],"properties":{}}'
assert(json_str == json.encode(json.decode(json_str)))
- cmj-JSON4Lua:工作不正常(空数组被编码为简单的空表)。
- dkjson:工作正常(使用元表上的“type”字段)。
- Fleece:未测试。
- jf-JSON:可选工作正常;默认情况下,空表始终编码为空对象。
- Lua-Yajl:工作不正常(空表始终编码为空数组)。
- mp-CJSON:工作不正常(空表始终编码为空对象)。
- sb-Json:未测试。
- th-LuaJSON:(v1.3) 工作正常(为数组分配特殊元表)。
- luci.json:解码为 nil,空表始终编码为空数组。
- lunajson:如果解码器被传递了嵌入数组长度的选项,则工作正常。
编码速度
- cmj-JSON4Lua:12 秒。
- dkjson:16 秒。
- Fleece:0.5 秒。
- jf-JSON:20 秒。
- Lua-Yajl:5.9 秒。
- mp-CJSON:1 秒。
- sb-Json:22 秒。
- th-LuaJSON:30 秒。
解码速度
- cmj-JSON4Lua:47 秒。
- dkjson:无 LPeg 28 秒,有 LPeg 8 秒。
- jf-JSON:30 秒。
- Lua-Yajl:4 秒。
- mp-CJSON:2 秒。
- sb-Json:122 秒。
- th-LuaJSON:9 秒(版本 1.2.2 需要 347 秒)。
对于速度测试,一个表被编码或解码了 100000 次。这些值不精确,使用其他数据时可能不同,但它们应该能提供一般性的参考。待办事项 - 在不知道表是什么的情况下,很难在这里运行新的测试?
另请参阅
- [JSONRPC4Lua] (5.0/5.1) - 适用于 Lua 的 JSON-RPC-over-http 客户端(或 CGILua 环境中的服务器)。
RecentChanges · preferences
编辑 · 历史
最后编辑于 2018 年 8 月 5 日上午 12:27 GMT (差异)