我正在开发一个简单的优化JSON函数.Lua使用表来表示数组,但在JSON中我需要在它们之间进行识别.使用以下代码:
t={
a="hi",
b=100
}
function table2json(t,formatted)
if type(t)~="table" then return nil,"Parameter is not a table. It is: "..type(t) end
local ret=""--return value
local lvl=0 --indentation level
local INDENT=" " --OPTION: the characters put in front of every line for indentation
function addToRet(str) if formatted then ret=ret..string.rep(INDENT,lvl)..str.."\n" else ret=ret..str end end
addToRet("{")
lvl=1
for k,v in pairs(t) do
local typeof=type(v)
if typeof=="string" then
addToRet(k..":\""..v.."\"")
elseif typeof=="number" then
addToRet(k..":"..v)
end
end
lvl=0
addToRet("}")
return ret
end
print(table2json(t,true))
Run Code Online (Sandbox Code Playgroud)
正如你在JSON参考中看到的那样,在Lua中object称为a table,它与a 不同array.
问题是如何检测表是否被用作数组?
任何更简单/更智能的解决方案?
如果你想要快速,简单,非侵入式的解决方案,大多数时候都可以工作,那么我只想检查索引1 - 如果它存在,那么表就是一个数组.当然,没有保证,但根据我的经验,表很少有数字键和其他键.你是否可以将某些对象误认为数组,以及你是否希望这种情况发生,这通常取决于你的使用场景 - 我想这对于一般的JSON库来说并不好.
编辑:对于科学,我去看看Lua CJSON是如何做的.它遍历所有对并检查所有键是否为整数,同时保持最大键(相关功能lua_array_length).然后它决定是否将表序列化为数组或对象,具体取决于表的稀疏程度(用户控制的比率),即索引为1,2,5,10的表可能会被序列化为数组而指数1,2,1000000将作为对象.我想这实际上是非常好的解决方案.
小智 6
这是基于 Lua 特定 #len 函数机制的更简单的检查。
function is_array(table)
if type(table) ~= 'table' then
return false
end
-- objects always return empty size
if #table > 0 then
return true
end
-- only object can have empty length with elements inside
for k, v in pairs(table) do
return false
end
-- if no elements it can be array and not at same time
return true
end
local a = {} -- true
local b = { 1, 2, 3 } -- true
local c = { a = 1, b = 1, c = 1 } -- false
Run Code Online (Sandbox Code Playgroud)
区分数组/非数组的最简单算法是这个:
local function is_array(t)
local i = 0
for _ in pairs(t) do
i = i + 1
if t[i] == nil then return false end
end
return true
end
Run Code Online (Sandbox Code Playgroud)
此处说明:https : //web.archive.org/web/20140227143701/http : //ericjmritz.name/2014/02/26/lua-is_array/
也就是说,您仍然会遇到空表的问题——它们是“数组”还是“散列”?
对于序列化 json 的特殊情况,我所做的是用元表中的字段标记数组。
-- use this when deserializing
local function mark_as_array(t)
setmetatable(t, {__isarray = true})
end
-- use this when serializing
local function is_array(t)
local mt = getmetatable(t)
return mt.__isarray
end
Run Code Online (Sandbox Code Playgroud)