我有一个不错的Lua表解析器,它可以打印出看起来很漂亮的Lua代码,我喜欢它...它的工作原理很漂亮。有一点小问题...如果我要打印具有任何整数键的表或数组,它会使用pairs循环遍历它(这不会讽刺地将代码弄乱了),但我宁愿在可能的情况下使用ipairs。因此,我想知道是否可以检查一个表(无需物理查看),如果它可以使用ipairs首先遍历该表,否则可以使用对。那么有没有办法从0开始而不是Lua的默认1开始循环?

Lua Table Parser(在Google上找到的基本代码,对其进行了更改,以使其打印出更友好的数组)...

function TableParser(name, object, tabs)
    local function serializeKeyForTable(k)
        if type(k)=="number" then
            return ""
        end
        if string.find(k,"[^A-z_-]") then
            return k
        end
        return k
    end
    local function serializeKey(k)
        if type(k)=="number" then
            if k == 0 then
                return "\t[" .. k .."] = "
            else
                return "\t"
            end
        end
        if string.find(k,"[^A-z_-]") then
            return "\t" .. k .. " = "
        end
        return "\t" .. k .. " = "
    end
    if not tabs then tabs = "" end
    local function serialize(name, object, tabs) -- = {
        local output = tabs .. (name ~= "" and name .. " = " or "") .. "{" .. "\n"
        for k,v in pairs(object) do
            if type(v) == "number" then
                output = output .. tabs .. serializeKey(k) .. v
            elseif type(v) == "string" then
                output = output .. tabs .. serializeKey(k) .. string.format("%q",v)
            elseif type(v) == "table" then
                output = output .. serialize(serializeKeyForTable(k), v, tabs.."\t")
            elseif type(v) == "boolean" then
                output = output .. tabs .. serializeKey(k) .. tostring(v)
            else
                output = output .. tabs .. serializeKey(k) .. "\"" .. tostring(v) .. "\""
            end
            if next(object,k) then
                output = output .. ",\n"
            end
        end
        return output .. "\n" .. tabs .. "}"
    end
    return serialize(name, object, tabs)
end

最佳答案

因此,我想知道是否可以检查一个表(无需物理查看),如果它可以使用ipairs首先遍历该表,否则可以使用对。

不要检查,只是做!首先使用ipairs并跟踪ipairs迭代器返回的最大密钥。然后使用pairs再次进行迭代,并忽略1ipairs中最大的键之间的所有整数键。

如果您真的想检查ipairs是否会做某事,请查看表中的索引1(rawget( object, 1 ) ~= nil)。如果不迭代表,则无法检查ipairs是否将覆盖表中的所有元素。

那么有没有办法从0开始而不是Lua的默认1开始循环?
ipairs(t)返回三个值:迭代器函数,作为状态变量的表t和初始索引值0。如果将-1用作初始索引值,则ipairs将在0处开始迭代(迭代器函数在使用索引值之前始终增加一):

t = { 1, 2, 3, [ 0 ] = 0 }
for i,v in ipairs( t ), t, -1 do  -- only use first value returned by ipairs
  print( i, v )
end

但是,请注意,Lua 5.2添加了对新元方法__ipairs的支持,该支持使您可以返回用于ipairs迭代的自定义迭代器三元组,并且在这种情况下返回的迭代器函数可能需要不同的状态和初始索引值。

编辑:
要将建议合并到代码中,请在for k,v in pairs(object) do -loop之前插入:
local largest = 0
for k,v in ipairs(object) do
    largest = k
    local t = type(v)
    if t == "table" then
        output = output .. tabs .. "\t" .. serialize( "", v, tabs.."\t" )
    elseif t == "string" then
        output = output .. tabs .. "\t" .. string.format("%q", v)
    else
        output = output .. tabs .. "\t" .. tostring(v)
    end
    output = output .. ",\n"
end

并在循环内添加一个附加的if语句以检查数组键:
for k,v in pairs(object) do
   if type(k) ~= "number" or k < 1 or k > largest or math.floor(k) ~= k then
       -- if type(v) == "number" then
       -- ...
   end
end

如果将此修改后的TableParser函数应用于下表:
local t = {
  1, 2, 3,
  value = "x",
  tab = {
    "a", "b", field = "y"
  }
}
print( TableParser( "", t ) )

输出为:
{
    1,
    2,
    3,
    tab = {
        "a",
        "b",
        field = "y"
    },
    value = "x"
}

但是正确地进行表序列化非常棘手。例如。您的实现不将循环或表作为键处理。有关某些实现,请参见Lua Wiki

07-28 02:53