如何将表格转储到控制台?
我遇到了显示包含嵌套表格(n-深度)的表格内容的麻烦。我想通过 print
语句或一些快速而不错的东西来将其转储到标准输出或控制台上,但是我无法弄清楚如何做到这一点。我正在寻找与使用 gdb 打印 NSDictionary
时获得的粗略等效物。
原文链接 https://stackoverflow.com/questions/9168058
欢迎浏览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
}
}
我知道这个问题已经被标记为已答复,但我想介绍一下我的自己的库。它叫做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
-- }
它适当地缩进子表,并正确处理“递归表”(即包含对自身的引用的表),因此它不会陷入无限循环。它以合理的方式对值进行排序。它还打印元表信息。
问候!
metalua 中的 table.tostring
方法实际上非常完整。它处理嵌套表,缩进级别是可变的,... 详见 https://github.com/fab13n/metalua/blob/master/src/lib/metalua/table2.lua。
-- 打印表格函数
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(在列表的最后一个元素后面写入了一个逗号),但是由于我只是快速编写一个原型,所以我会让你自己适应你的需求。
将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
对我来说这个函数非常好用...
如果要求 "快而简单"
我发现这个函数很有用。由于递归,它还可以打印嵌套表。它的输出格式可能不是最漂亮的,但对于这样一个简单的函数来说,它很难被打败,特别是用于调试。
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,} ,}
这是我支持排除表格和用户数据的版本。
-- 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 ###
注意,根节点不会排除排除列表中的元素。
如之前提到的,你需要亲自写代码。
以下是我自己写的一个简单版:
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"
有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
我使用自己的函数来打印表格的内容,但不确定它能在你的环境中正常工作:
--- 一个辅助函数用于打印表格的内容。
---@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
添加另一个版本。这个版本尝试迭代遍历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
最简单的方式,包括循环引用处理:
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
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
)
)
现在函数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
```lua
local json = require('cjson')
json_string = json.encode(this_table)
print (json_string)
```
将数据转换为 JSON 格式,然后打印输出。
创建了这个版本来打印带缩进的表格。可能可以扩展为递归工作。
function printtable(table, indent)
print(tostring(table) .. '\n')
for index, value in pairs(table) do
print(' ' .. tostring(index) .. ' : ' .. tostring(value) .. '\n')
end
end
下面是一个格式化字符串中变量值的小片段:
-- 在格式化字符串中转储变量的值
--
-- @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
可以在 这里 中找到这个片段。
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
抱歉,您必须自己编写代码。我编写了这个函数,它可能对您有用。
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