如何将表格转储到控制台?

我遇到了显示包含嵌套表格(n-深度)的表格内容的麻烦。我想通过 print 语句或一些快速而不错的东西来将其转储到标准输出或控制台上,但是我无法弄清楚如何做到这一点。我正在寻找与使用 gdb 打印 NSDictionary 时获得的粗略等效物。

原文链接 https://stackoverflow.com/questions/9168058

点赞
stackoverflow用户622310
stackoverflow用户622310

抱歉,您必须自己编写代码。我编写了这个函数,它可能对您有用。

function printtabletableindentindent = indent or 0;

  local keys = {};

  for k in pairs(table) do
    keys[#keys+1] = k;
    table.sort(keys, function(a, b)
      local ta, tb = type(a), type(b);
      if (ta ~= tb) then
        return ta < tb;
      else
        return a < b;
      end
    end);
  end

  print(string.rep('  ', indent)..'{');
  indent = indent + 1;
  for k, v in pairs(table) do

    local key = k;
    if (type(key) == 'string') then
      if not (string.match(key, '^[A-Za-z_][0-9A-Za-z_]*$')) then
        key = "['"..key.."']";
      end
    elseif (type(key) == 'number') then
      key = "["..key.."]";
    end

    if (type(v) == 'table') then
      if (next(v)) then
        printf("%s%s =", string.rep('  ', indent), tostring(key));
        printtable(v, indent);
      else
        printf("%s%s = {},", string.rep('  ', indent), tostring(key));
      end
    elseif (type(v) == 'string') then
      printf("%s%s = %s,", string.rep('  ', indent), tostring(key), "'"..v.."'");
    else
      printf("%s%s = %s,", string.rep('  ', indent), tostring(key), tostring(v));
    end
  end
  indent = indent - 1;
  print(string.rep('  ', indent)..'}');
end
2012-02-06 22:17:10
stackoverflow用户221509
stackoverflow用户221509

欢迎浏览Lua Wiki的表序列化。它列出了几种将表转储到控制台的方式。

你只需要选择最适合你的一种。有很多种方法可以做到这一点,但我通常最终使用来自Penlight的方法:

> t = { a = { b = { c = "Hello world!", 1 }, 2, d = { 3 } } }
> require 'pl.pretty'.dump(t)
{
  a = {
    d = {
      3
    },
    b = {
      c = "Hello world!",
      1
    },
    2
  }
}
2012-02-06 22:30:56
stackoverflow用户312586
stackoverflow用户312586

我知道这个问题已经被标记为已答复,但我想介绍一下我的自己的库。它叫做inspect.lua,你可以在这里找到它:

https://github.com/kikito/inspect.lua

它只是一个单独的文件,你可以从任何其他文件中引用。它返回一个函数,可以将任何Lua值转换为可读的字符串:

local inspect = require('inspect')

print(inspect({1,2,3})) -- {1, 2, 3}
print(inspect({a=1,b=2})
-- {
--   a = 1
--   b = 2
-- }

它适当地缩进子表,并正确处理“递归表”(即包含对自身的引用的表),因此它不会陷入无限循环。它以合理的方式对值进行排序。它还打印元表信息。

问候!

2012-02-07 08:58:53
stackoverflow用户1051634
stackoverflow用户1051634

metalua 中的 table.tostring 方法实际上非常完整。它处理嵌套表,缩进级别是可变的,... 详见 https://github.com/fab13n/metalua/blob/master/src/lib/metalua/table2.lua

2012-02-07 11:33:35
stackoverflow用户1205792
stackoverflow用户1205792
-- 打印表格函数
function printTable(list, i)

    local listString = ''
    -- 如果是列表的开头,就写入 {
    if not i then
        listString = listString .. '{'
    end

    i = i or 1
    local element = list[i]

    -- 如果当前元素不存在,说明列表遍历完了
    if not element then
        return listString .. '}'
    end

    -- 如果当前元素是列表,继续递归调用打印函数
    if(type(element) == 'table') then
        listString = listString .. printTable(element)
    else
        listString = listString .. element
    end

    -- 继续打印逗号和下一个元素
    return listString .. ', ' .. printTable(list, i + 1)

end

local table = {1, 2, 3, 4, 5, {'a', 'b'}, {'G', 'F'}}
print(printTable(table))

嗨,这里是一段纯 Lua 的简单代码,它有一个 bug(在列表的最后一个元素后面写入了一个逗号),但是由于我只是快速编写一个原型,所以我会让你自己适应你的需求。

2012-02-13 01:20:55
stackoverflow用户1070906
stackoverflow用户1070906

tbl中的内容以缩进的形式打印出来。indent可以设置初始缩进等级的大小。

function tprint (tbl, indent)
  if not indent then indent = 0 end
  for k, v in pairs(tbl) do
    formatting = string.rep("  ", indent) .. k .. ": "
    if type(v) == "table" then
      print(formatting)
      tprint(v, indent+1)
    elseif type(v) == 'boolean' then
      print(formatting .. tostring(v))
    else
      print(formatting .. v)
    end
  end
end

来自这里:https://gist.github.com/ripter/4270799

对我来说这个函数非常好用...

2014-03-17 16:36:36
stackoverflow用户134702
stackoverflow用户134702

如果要求 "快而简单"

我发现这个函数很有用。由于递归,它还可以打印嵌套表。它的输出格式可能不是最漂亮的,但对于这样一个简单的函数来说,它很难被打败,特别是用于调试。

function dump(o)
   if type(o) == 'table' then
      local s = '{ '
      for k,v in pairs(o) do
         if type(k) ~= 'number' then k = '"'..k..'"' end
         s = s .. '['..k..'] = ' .. dump(v) .. ','
      end
      return s .. '} '
   else
      return tostring(o)
   end
end

例如:

local people = {
   {
      name = "Fred",
      address = "16 Long Street",
      phone = "123456"
   },

   {
      name = "Wilma",
      address = "16 Long Street",
      phone = "123456"
   },

   {
      name = "Barney",
      address = "17 Long Street",
      phone = "123457"
   }

}

print("People:", dump(people))

打印以下输出:

People: { [1] = { ["address"] = 16 Long Street,["phone"] = 123456,["name"] = Fred,} ,[2] = { ["address"] = 16 Long Street,["phone"] = 123456,["name"] = Wilma,} ,[3] = { ["address"] = 17 Long Street,["phone"] = 123457,["name"] = Barney,} ,}

2014-11-19 22:45:55
stackoverflow用户4416341
stackoverflow用户4416341

这是我支持排除表格和用户数据的版本。

-- Lua Table View by Elertan
table.print = function(t, exclusions)
    local nests = 0
    if not exclusions then exclusions = {} end
    local recurse = function(t, recurse, exclusions)
        indent = function()
            for i = 1, nests do
                io.write("    ")
            end
        end
        local excluded = function(key)
            for k,v in pairs(exclusions) do
                if v == key then
                    return true
                end
            end
            return false
        end
        local isFirst = true
        for k,v in pairs(t) do
            if isFirst then
                indent()
                print("|")
                isFirst = false
            end
            if type(v) == "table" and not excluded(k) then
                indent()
                print("|-> "..k..": "..type(v))
                nests = nests + 1
                recurse(v, recurse, exclusions)
            elseif excluded(k) then
                indent()
                print("|-> "..k..": "..type(v))
            elseif type(v) == "userdata" or type(v) == "function" then
                indent()
                print("|-> "..k..": "..type(v))
            elseif type(v) == "string" then
                indent()
                print("|-> "..k..": ".."\""..v.."\"")
            else
                indent()
                print("|-> "..k..": "..v)
            end
        end
        nests = nests - 1
    end

    nests = 0
    print("### START TABLE ###")
    for k,v in pairs(t) do
        print("root")
        if type(v) == "table" then
            print("|-> "..k..": "..type(v))
            nests = nests + 1
            recurse(v, recurse, exclusions)
        elseif type(v) == "userdata" or type(v) == "function" then
            print("|-> "..k..": "..type(v))
        elseif type(v) == "string" then
            print("|-> "..k..": ".."\""..v.."\"")
        else
            print("|-> "..k..": "..v)
        end
    end
    print("### END TABLE ###")
end

这是一个例子:

t = {
    location = {
       x = 10,
       y = 20
    },
    size = {
      width = 100000000,
      height = 1000,
    },
    name = "Sidney",
    test = {
        hi = "lol",
    },
    anotherone = {
        1,
        2,
        3
    }
}

table.print(t, { "test" })

输出:

   ### START TABLE ###
root
|-> size: table
    |
    |-> height: 1000
    |-> width: 100000000
root
|-> location: table
    |
    |-> y: 20
    |-> x: 10
root
|-> anotherone: table
    |
    |-> 1: 1
    |-> 2: 2
    |-> 3: 3
root
|-> test: table
root
|-> name: "Sidney"
### END TABLE ###

注意,根节点不会排除排除列表中的元素。

2015-02-20 12:58:01
stackoverflow用户7263119
stackoverflow用户7263119

如之前提到的,你需要亲自写代码。

以下是我自己写的一个简单版:

function tprint(t, s)
    for k, v in pairs(t) do
        local kfmt = '["' .. tostring(k) .. '"]'
        if type(k) ~= 'string' then
            kfmt = '[' .. k .. ']'
        end
        local vfmt = '"' .. tostring(v) .. '"'
        if type(v) == 'table' then
            tprint(v, (s or '')..kfmt)
        else
            if type(v) ~= 'string' then
                vfmt = tostring(v)
            end
            print(type(t) .. (s or '') .. kfmt .. ' = ' .. vfmt)
        end
    end
end

例如:

local mytbl = {['1'] = 'a', 2, 3, b = 'c', t = {d = 1}}
tprint(mytbl)

运行结果(Lua 5.0):

table[1] = 2
table[2] = 3
table["1"] = "a"
table["t"]["d"] = 1
table["b"] = "c"
2017-11-20 12:50:49
stackoverflow用户1091436
stackoverflow用户1091436

有2种解决方案需要提到:一个是快而简单的解决方案,另一个则是更完善且对所有键和值进行转义但代码较长。

简单且快速的解决方案(只针对“安全”输入):

local function format_any_value(obj, buffer)
    local _type = type(obj)
    if _type == "table" then
        buffer[#buffer + 1] = '{"'
        for key, value in next, obj, nil do
            buffer[#buffer + 1] = tostring(key) .. '":'
            format_any_value(value, buffer)
            buffer[#buffer + 1] = ',"'
        end
        buffer[#buffer] = '}' -- 注意覆盖
    elseif _type == "string" then
        buffer[#buffer + 1] = '"' .. obj .. '"'
    elseif _type == "boolean" or _type == "number" then
        buffer[#buffer + 1] = tostring(obj)
    else
        buffer[#buffer + 1] = '"???' .. _type .. '???"'
    end
end

使用:

local function format_as_json(obj)
    if obj == nil then return "null" else
        local buffer = {}
        format_any_value(obj, buffer)
        return table.concat(buffer)
    end
end

local function print_as_json(obj)
    print(_format_as_json(obj))
end

print_as_json {1, 2, 3}
print_as_json(nil)
print_as_json("string")
print_as_json {[1] = 1, [2] = 2, three = { { true } }, four = "four"}

带有键/值转义的正确解决方案

我在纯 Lua 中为这种特定用例编写了一个小型库:https://github.com/vn971/fast_json_encode

或者具体来说,这个文件包括一个格式化器和一个打印机:https://github.com/vn971/fast_json_encode/blob/master/json_format.lua

2017-12-09 08:30:45
stackoverflow用户3379140
stackoverflow用户3379140

我使用自己的函数来打印表格的内容,但不确定它能在你的环境中正常工作:

--- 一个辅助函数用于打印表格的内容。
---@param tbl table @要打印的表格。
---@param depth number @遍历和打印子表的深度。
---@param n number @不要手动设置这个变量。通过递归控制格式化。
function PrintTable(tbl, depth, n)
  n = n or 0;
  depth = depth or 5;

  if (depth == 0) then
      print(string.rep(' ', n).."...");
      return;
  end

  if (n == 0) then
      print(" ");
  end

  for key, value in pairs(tbl) do
      if (key and type(key) == "number" or type(key) == "string") then
          key = string.format("[\"%s\"]", key);

          if (type(value) == "table") then
              if (next(value)) then
                  print(string.rep(' ', n)..key.." = {");
                  PrintTable(value, depth - 1, n + 4);
                  print(string.rep(' ', n).."},");
              else
                  print(string.rep(' ', n)..key.." = {},");
              end
          else
              if (type(value) == "string") then
                  value = string.format("\"%s\"", value);
              else
                  value = tostring(value);
              end

              print(string.rep(' ', n)..key.." = "..value..",");
          end
      end
  end

  if (n == 0) then
      print(" ");
  end
end
2019-02-08 13:14:06
stackoverflow用户3779853
stackoverflow用户3779853

添加另一个版本。这个版本尝试迭代遍历userdata。

function inspect(o,indent)
    if indent == nil then indent = 0 end
    local indent_str = string.rep("    ", indent)
    local output_it = function(str)
        print(indent_str..str)
    end

    local length = 0

    local fu = function(k, v)
        length = length + 1
        if type(v) == "userdata" or type(v) == 'table' then
            output_it(indent_str.."["..k.."]")
            inspect(v, indent+1)
        else
            output_it(indent_str.."["..k.."] "..tostring(v))
        end
    end

    local loop_pairs = function()
        for k,v in pairs(o) do fu(k,v) end
    end

    local loop_metatable_pairs = function()
        for k,v in pairs(getmetatable(o)) do fu(k,v) end
    end

    if not pcall(loop_pairs) and not pcall(loop_metatable_pairs) then
        output_it(indent_str.."[[??]]")
    else
        if length == 0 then
            output_it(indent_str.."{}")
        end
    end
end
2019-04-15 12:41:44
stackoverflow用户6367889
stackoverflow用户6367889

最简单的方式,包括循环引用处理:

function dump(t, indent, done)
    done = done or {}
    indent = indent or 0

    done[t] = true

    for key, value in pairs(t) do
        print(string.rep("\t", indent))

        if type(value) == "table" and not done[value] then
            done[value] = true
            print(key, ":\n")

            dump(value, indent + 2, done)
            done[value] = nil
        else
            print(key, "\t=\t", value, "\n")
        end
    end
end
2020-11-12 01:16:59
stackoverflow用户13958932
stackoverflow用户13958932

lua中转储表的简单示例

我建议使用 serpent.lua

local function parser(value, indent, subcategory)
  local indent = indent or 2
  local response = '(\n'
  local subcategory = type(subcategory) == 'number' and subcategory or indent
  for key, value in pairs(value) do
    if type(value) == 'table' then
      value = parser(value, indent, subcategory + indent)

    elseif type(value) == 'string' then
      value = '\''.. value .. '\''

    elseif type(value) ~= 'number' then
      value = tostring(value)
    end

    if type(tonumber(key)) == 'number' then
        key = '[' .. key .. ']'
   elseif not key:match('^([A-Za-z_][A-Za-z0-9_]*)$') then
      key = '[\'' .. key .. '\']'
    end
    response = response .. string.rep(' ', subcategory) .. key .. ' = ' .. value .. ',\n'
  end
  return response .. string.rep(' ', subcategory - indent) .. ')'

end

示例

response = parser{1,2,3, {ok = 10, {}}}
print(response)

结果

(
  [1] = 1,
  [2] = 2,
  [3] = 3,
  [4] = (
    [1] = (),
    ok = 10
  )
)
2021-07-21 02:34:56
stackoverflow用户12968803
stackoverflow用户12968803

现在函数print可以打印(平面)表格!

oprint = print -- 原打印
print = function (...)
    if type(...) == "table" then
        local str = ''
        local amount = 0
        for i,v in pairs(...) do
            amount=amount+1
            local pre = type(i) == "string" and i.."=" or ""
            str = str .. pre..tostring(v) .. "\t"
        end
        oprint('#'..amount..':', str)
    else
        oprint(...)
    end
end

例如:

print ({x=7, y=9, w=11, h="height", 7, 8, 9})

将打印:

#7: 7 8 9 y=9 x=7 h=height w=11

同样的方法也可以用新函数tostring来实现:

otostring = tostring -- 原要字符串
tostring = function (...)
    if type(...) == "table" then
        local str = '{'
        for i,v in pairs(...) do
            local pre = type(i) == "string" and i.."=" or ""
            str = str .. pre..tostring(v) .. ", "
        end
        str = str:sub(1, -3)
        return str..'}'
    else
        return otostring(...)
    end
end
2021-08-20 14:42:33
stackoverflow用户3528340
stackoverflow用户3528340
    ```lua
    local json = require('cjson')
    json_string = json.encode(this_table)
    print (json_string)
    ```
    将数据转换为 JSON 格式,然后打印输出。
2021-10-09 00:01:12
stackoverflow用户4052701
stackoverflow用户4052701

创建了这个版本来打印带缩进的表格。可能可以扩展为递归工作。

function printtable(table, indent)
  print(tostring(table) .. '\n')
  for index, value in pairs(table) do
    print('    ' .. tostring(index) .. ' : ' .. tostring(value) .. '\n')
  end
end
2022-04-13 23:12:59
stackoverflow用户13476089
stackoverflow用户13476089

下面是一个格式化字符串中变量值的小片段:

-- 在格式化字符串中转储变量的值
--
-- @param o    table       可转储对象
-- @param tbs  string|nil  制表字符串,默认为'  '
-- @param tb   number|nil  初始化制表级别,默认为0
-- @return     string
local function dump(o, tbs, tb)
  tb = tb or 0
  tbs = tbs or '  '
  if type(o) == 'table' then
    local s = '{'
    if (next(o)) then s = s .. '\n' else return s .. '}' end
    tb = tb + 1
    for k,v in pairs(o) do
      if type(k) ~= 'number' then k = '"' .. k .. '"' end
      s = s .. tbs:rep(tb) .. '[' .. k .. '] = ' .. dump(v, tbs, tb)
      s = s .. ',\n'
    end
    tb = tb - 1
    return s .. tbs:rep(tb) .. '}'
  else
    return tostring(o)
  end
end

可以在 这里 中找到这个片段。

2022-06-19 12:54:20