【问题标题】:Lua: Check if a table can be looped through via ipairs & ipairs starting at 0Lua:检查表是否可以通过 ipairs 和 ipairs 从 0 开始循环
【发布时间】:2015-02-24 18:48:00
【问题描述】:

我有一个漂亮的小 Lua 表解析器,它打印出漂亮的 lua 代码,我喜欢它……它工作得很好。有一个小问题...如果我要打印一个包含任何整数键的表或数组,它会使用pairs 循环遍历它(讽刺的是这不会弄乱代码),但我宁愿它使用@987654322 @ 如果可能的话。所以我想知道是否可以检查一个表(无需实际查看它)是否可以先使用 ipairs 循环遍历它,否则使用对。那么有没有办法从 0 而不是 Lua 默认的 1 开始循环呢?

Lua 表解析器(在 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

【问题讨论】:

  • 它不是“解析器”。恰恰相反:它是一个序列化程序(或者,更准确地说,是一个“漂亮的打印机”,b/c 它关心美学)。
  • if string.find(k, .. 似乎完全没有意义。无论条件结果如何,您在两种情况下都返回相同的结果。

标签: parsing lua integer lua-table


【解决方案1】:

所以我想知道是否可以检查一个表(无需实际查看)是否可以先使用 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 了解一些实现。

【讨论】:

  • 感谢分享,但不管我现在怎么做,我要么得到双倍的结果,要么得到一堆空白表,当它们应该有数据时......想法?你能告诉我一些例子,包括嵌套表吗?
  • 很好的实现,只有障碍是任何键 [0] 最后打印,但可能会忽略这一点。如果我可以问,什么是周期?另外,为什么/如何将表作为键?
  • @B1313:如果将ipairs(object) 更改为ipairs(object),object,-1 并将k &lt; 1 更改为k &lt; 0,则索引0 处的值将与数组部分一起打印。关于周期:t = {}; t[1] = t。一个表可以(直接或间接)包含对其自身的引用,或者两个表条目可以引用同一个表。将表视为键:例如,查找表/缓存。重点是:Lua 允许,所以有可能在某个时候你会遇到这样的情况,你最好做好处理它的准备。
【解决方案2】:

无论是否有意义,您始终可以使用pairsipairs 来迭代表。

  • ipairs 迭代数组中存在的序列(这意味着顺序整数键从 1 开始,直到第一个缺失值),除非被元方法 __ipairs (5.2) 覆盖。

  • pairs 使用 next 迭代所有键值对(因此以未指定的顺序),除非被元方法 __pairs (5.2) 覆盖。

这意味着ipairs 通常不会枚举任何键值对pairs 不会显示。

并且没有办法验证ipairs是否会枚举所有键pairs会枚举,而是枚举所有内容并手动测试。

顺便说一句:您可以创建自己的迭代器,它首先迭代序列,然后迭代其他所有内容:

function my_iter(t)
    local k, cap
    return function()
        local v
        if k == nil then k, cap = 0 end
        if not cap then
            k = k + 1
            v = t[k]
            if v ~= nil then return k, v end
            cap, k = k
        end
        repeat k, v = next(k)
        until type(k) ~= "number" or 0 < k and k < cap and math.ceil(k) == k
        return k, v
    end
end

虽然最好只对键进行排序以进行漂亮的打印:

function sorted_iter(t)
    local keys, index = {}, 0
    for k in next, t do
        keys[#keys + 1] = k
    end
    table.sort(keys)
    return function()
        index = index + 1
        local k = keys[index]
        return k, t[k]
    end
end

【讨论】:

    猜你喜欢
    • 2017-11-16
    • 2019-08-02
    • 2017-12-18
    • 2012-02-15
    • 2021-06-12
    • 2017-08-18
    • 2017-07-06
    • 2018-05-26
    • 2015-02-17
    相关资源
    最近更新 更多