How to dump a table to console?
我无法显示包含嵌套表(n-deep)的表的内容。我想通过
我发现这个很有用。因为如果递归它也可以打印嵌套表。它没有在输出中给出最漂亮的格式,但是对于这样一个简单的功能,它很难在调试时被击败。
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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,} ,}
我知道这个问题已经被标记为已回答,但让我在这里插入我自己的库。它叫做inspect.lua,你可以在这里找到它:
https://github.com/kikito/inspect.lua
它只是一个您可以从任何其他文件中获取的文件。它返回一个将任何 Lua 值转换为人类可读字符串的函数:
1 2 3 4 5 6 7 8 | local inspect = require('inspect') print(inspect({1,2,3})) -- {1, 2, 3} print(inspect({a=1,b=2}) -- { -- a = 1 -- b = 2 -- } |
它正确缩进子表,并正确处理"递归表"(包含对自身的引用的表),因此它不会陷入无限循环。它以合理的方式对值进行排序。它还打印元表信息。
问候!
请随意浏览关于表序列化的 Lua Wiki。它列出了如何将表转储到控制台的几种方法。
您只需要选择最适合您的。有很多方法可以做到这一点,但我通常最终使用 Penlight 中的一种:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | > t = { a = { b = { c ="Hello world!", 1 }, 2, d = { 3 } } } > require 'pl.pretty'.dump(t) { a = { d = { 3 }, b = { c ="Hello world!", 1 }, 2 } } |
找到了这个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | -- Print contents of `tbl`, with indentation. -- `indent` sets the initial level of indentation. 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
对我来说很好用……
我见过的大多数纯 lua 打印表函数都存在深度递归问题
并且在太深时往往会导致堆栈溢出。这个印刷品
我写的表函数没有这个问题。由于它处理连接的方式,它还应该能够处理非常大的表。在我个人对这个函数的使用中,它在大约一秒钟内输出了 63k 行到文件。
输出还保留了lua语法,脚本可以很容易地修改
如果修改为允许,则通过将输出写入文件来进行简单的持久存储
仅要格式化的数字、布尔值、字符串和表格数据类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | function print_table(node) local cache, stack, output = {},{},{} local depth = 1 local output_str ="{\ " while true do local size = 0 for k,v in pairs(node) do size = size + 1 end local cur_index = 1 for k,v in pairs(node) do if (cache[node] == nil) or (cur_index >= cache[node]) then if (string.find(output_str,"}",output_str:len())) then output_str = output_str ..",\ " elseif not (string.find(output_str,"\ ",output_str:len())) then output_str = output_str .."\ " end -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings table.insert(output,output_str) output_str ="" local key if (type(k) =="number" or type(k) =="boolean") then key ="["..tostring(k).."]" else key ="['"..tostring(k).."']" end if (type(v) =="number" or type(v) =="boolean") then output_str = output_str .. string.rep('\\t',depth) .. key .." ="..tostring(v) elseif (type(v) =="table") then output_str = output_str .. string.rep('\\t',depth) .. key .." = {\ " table.insert(stack,node) table.insert(stack,v) cache[node] = cur_index+1 break else output_str = output_str .. string.rep('\\t',depth) .. key .." = '"..tostring(v).."'" end if (cur_index == size) then output_str = output_str .."\ " .. string.rep('\\t',depth-1) .."}" else output_str = output_str .."," end else -- close the table if (cur_index == size) then output_str = output_str .."\ " .. string.rep('\\t',depth-1) .."}" end end cur_index = cur_index + 1 end if (size == 0) then output_str = output_str .."\ " .. string.rep('\\t',depth-1) .."}" end if (#stack > 0) then node = stack[#stack] stack[#stack] = nil depth = cache[node] == nil and depth + 1 or depth - 1 else break end end -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings table.insert(output,output_str) output_str = table.concat(output) print(output_str) end |
这是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 | local t = { ["abe"] = {1,2,3,4,5}, "string1", 50, ["depth1"] = { ["depth2"] = { ["depth3"] = { ["depth4"] = { ["depth5"] = { ["depth6"] = { ["depth7"]= { ["depth8"] = { ["depth9"] = { ["depth10"] = {1000}, 900}, 800},700},600},500}, 400 }, 300}, 200}, 100}, ["ted"] = {true,false,"some text"}, "string2", [function() return end] = function() return end, 75 } print_table(t) |
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | { [1] = 'string1', [2] = 50, [3] = 'string2', [4] = 75, ['abe'] = { [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 5 }, ['function: 06472B70'] = 'function: 06472A98', ['depth1'] = { [1] = 100, ['depth2'] = { [1] = 200, ['depth3'] = { [1] = 300, ['depth4'] = { [1] = 400, ['depth5'] = { [1] = 500, ['depth6'] = { [1] = 600, ['depth7'] = { [1] = 700, ['depth8'] = { [1] = 800, ['depth9'] = { [1] = 900, ['depth10'] = { [1] = 1000 } } } } } } } } } }, ['ted'] = { [1] = true, [2] = false, [3] = 'some text' } } |
如前所述,您必须编写它。
这是我的简陋版本:(超级基本的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 |
示例:
1 2 | local mytbl = { ['1']="a", 2, 3, b="c", t={d=1} } tprint(mytbl) |
输出(Lua 5.0):
1 2 3 4 5 | table[1] = 2 table[2] = 3 table["1"] ="a" table["t"]["d"] = 1 table["b"] ="c" |
最简单的方法,循环引用处理等等:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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,":\ ") dump(value, indent + 2, done) done[value] = nil else print(key,"\\t=\\t", value,"\ ") end end end |
我使用自己的函数来打印表格的内容,但不确定它在您的环境中的转换效果如何:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | ---A helper function to print a table's contents. ---@param tbl table @The table to print. ---@param depth number @The depth of sub-tables to traverse through and print. ---@param n number @Do NOT manually set this. This controls formatting through recursion. 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 |
格式为JSON(以后可以在IDE中"美化"):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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] = '}' -- note the overwrite 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 |
用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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"} |
顺便说一句,我还写了其他几个解决方案:一个非常快的解决方案,一个带有特殊字符转义的解决方案:https://github.com/vn971/fast_json_encode
恐怕您必须自己编写代码。这是我写的,可能对你有用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | function printtable(table, indent) indent = 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 |
metalua的
见 https://github.com/fab13n/metalua/blob/master/src/lib/metalua/table2.lua
这是我的版本,支持排除表和用户数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | -- 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 |
这是一个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | t = { location = { x = 10, y = 20 }, size = { width = 100000000, height = 1000, }, name ="Sidney", test = { hi ="lol", }, anotherone = { 1, 2, 3 } } table.print(t, {"test" }) |
打印:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ### 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 | |-> hi:"lol" root |-> name:"Sidney" ### END TABLE ### |
请注意,根目录不会删除排除项
添加另一个版本。这个也尝试迭代用户数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | --~ print a table function printTable(list, i) local listString = '' --~ begin of the list so write the { if not i then listString = listString .. '{' end i = i or 1 local element = list[i] --~ it may be the end of the list if not element then return listString .. '}' end --~ if the element is a list too call it recursively 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 编写了一个简单的代码,它有一个错误(在列表的最后一个元素之后写一个逗号)但是我如何快速将它作为原型编写,我会让它适应你它满足您的需求。
转成json再打印。
1 2 3 | local json = require('cjson') json_string = json.encode(this_table) print (json_string) |
在 lua 中转储表的简单示例
我建议使用 serpent.lua
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | local function parser(value, indent, subcategory) local indent = indent or 2 local response = '(\ ' 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 .. ',\ ' end return response .. string.rep(' ', subcategory - indent) .. ')' end |
示例
1 2 | response = parser{1,2,3, {ok = 10, {}}} print(response) |
结果
1 2 3 4 5 6 7 8 9 | ( [1] = 1, [2] = 2, [3] = 3, [4] = ( [1] = (), ok = 10 ) ) |
我已经谦虚地修改了一点 Alundaio 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | -- by Alundaio -- KK modified 11/28/2019 function dump_table_to_string(node, tree, indentation) local cache, stack, output = {},{},{} local depth = 1 if type(node) ~="table" then return"only table type is supported, got" .. type(node) end if nil == indentation then indentation = 1 end local NEW_LINE ="\ " local TAB_CHAR ="" if nil == tree then NEW_LINE ="\ " elseif not tree then NEW_LINE ="" TAB_CHAR ="" end local output_str ="{" .. NEW_LINE while true do local size = 0 for k,v in pairs(node) do size = size + 1 end local cur_index = 1 for k,v in pairs(node) do if (cache[node] == nil) or (cur_index >= cache[node]) then if (string.find(output_str,"}",output_str:len())) then output_str = output_str .."," .. NEW_LINE elseif not (string.find(output_str,NEW_LINE,output_str:len())) then output_str = output_str .. NEW_LINE end -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings table.insert(output,output_str) output_str ="" local key if (type(k) =="number" or type(k) =="boolean") then key ="["..tostring(k).."]" else key ="['"..tostring(k).."']" end if (type(v) =="number" or type(v) =="boolean") then output_str = output_str .. string.rep(TAB_CHAR,depth*indentation) .. key .." ="..tostring(v) elseif (type(v) =="table") then output_str = output_str .. string.rep(TAB_CHAR,depth*indentation) .. key .." = {" .. NEW_LINE table.insert(stack,node) table.insert(stack,v) cache[node] = cur_index+1 break else output_str = output_str .. string.rep(TAB_CHAR,depth*indentation) .. key .." = '"..tostring(v).."'" end if (cur_index == size) then output_str = output_str .. NEW_LINE .. string.rep(TAB_CHAR,(depth-1)*indentation) .."}" else output_str = output_str .."," end else -- close the table if (cur_index == size) then output_str = output_str .. NEW_LINE .. string.rep(TAB_CHAR,(depth-1)*indentation) .."}" end end cur_index = cur_index + 1 end if (size == 0) then output_str = output_str .. NEW_LINE .. string.rep(TAB_CHAR,(depth-1)*indentation) .."}" end if (#stack > 0) then node = stack[#stack] stack[#stack] = nil depth = cache[node] == nil and depth + 1 or depth - 1 else break end end -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings table.insert(output,output_str) output_str = table.concat(output) return output_str end |
然后:
1 2 3 4 5 6 7 8 9 | print(dump_table_to_string("AA", true,3)) print(dump_table_to_string({"AA","BB"}, true,3)) print(dump_table_to_string({"AA","BB"})) print(dump_table_to_string({"AA","BB"},false)) print(dump_table_to_string({"AA","BB",{22,33}},true,2)) |
给予:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | only table type is supported, got string { [1] = 'AA', [2] = 'BB' } { [1] = 'AA', [2] = 'BB' } {[1] = 'AA',[2] = 'BB'} { [1] = 'AA', [2] = 'BB', [3] = { [1] = 22, [2] = 33 } } |
现在函数 print 可以打印(平面)表格了!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | oprint = print -- origin 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 |
例如:
1 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | otostring = tostring -- origin 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 |