Lua中的table.toString(tableName)和table.fromString(stringTable)函数是什么?

13
我想将一个2D的lua表格转换成字符串,然后再通过这个新创建的字符串将其转换回表格。这个过程似乎被称为序列化,并在下面的URL中进行了讨论,但我很难理解代码,希望这里有人能提供一个简单的table.toString和table.fromString函数。
http://lua-users.org/wiki/TableSerialization

8个回答

23

我正在使用下面的代码来序列化表格:

function serializeTable(val, name, skipnewlines, depth)
    skipnewlines = skipnewlines or false
    depth = depth or 0

    local tmp = string.rep(" ", depth)

    if name then tmp = tmp .. name .. " = " end

    if type(val) == "table" then
        tmp = tmp .. "{" .. (not skipnewlines and "\n" or "")

        for k, v in pairs(val) do
            tmp =  tmp .. serializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "")
        end

        tmp = tmp .. string.rep(" ", depth) .. "}"
    elseif type(val) == "number" then
        tmp = tmp .. tostring(val)
    elseif type(val) == "string" then
        tmp = tmp .. string.format("%q", val)
    elseif type(val) == "boolean" then
        tmp = tmp .. (val and "true" or "false")
    else
        tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\""
    end

    return tmp
end

创建的代码可以使用loadstring()执行:http://www.lua.org/manual/5.1/manual.html#pdf-loadstring,如果你已经传递了"name"参数(或在之后附加):

s = serializeTable({a = "foo", b = {c = 123, d = "foo"}})
print(s)
a = loadstring(s)()

2
你知道吗,tostring函数也适用于布尔值。tostring(true)的结果是"true"。 - Ponkadoodle
这段代码无法处理像 a={}; a[1]=2; 这样的情况。({1=2} 无法转为字符串) 对于 nil 等情况也是如此。不过,对于漂亮的打印输出,已经有其他库可以使用了。 - user202729

11

lhf发布的代码示例比您链接的页面中的任何代码示例都简单得多,因此希望您能更好地理解它。将其调整为输出字符串而不是打印输出的代码如下:

t = {
{11,12,13},
{21,22,23},
}

local s = {"return {"}
for i=1,#t do
  s[#s+1] = "{"
  for j=1,#t[i] do
    s[#s+1] = t[i][j]
    s[#s+1] = ","
  end
  s[#s+1] = "},"
end
s[#s+1] = "}"
s = table.concat(s)

print(s)

序列化的基本思想是从类似表格的数据结构中获取所有数据位,然后遍历该数据结构,同时构建一个字符串,其中包含所有数据位和格式化字符。


感谢您的代码。我的意思是重新定义“print”或使用不同的函数来收集输出结果并将其存储在表中,以便您可以尽可能地保留我的原始代码。 - lhf
2
我讨厌函数重载,因为我总是忘记我已经更改了它。 - jhocking
1
我认为 #t 需要进行一些迭代来计算表的长度。使用自己的长度计数器变量可能更有效率。 - Ponkadoodle
这个答案难道只适用于数组吗?假设你的索引从1开始并遵循顺序……那么对于通用表格(由任何值索引,比如字符串……也就是哈希表)呢? - zertyz
1
我强烈建议使用JSON来实现这个目的(即dosimple在https://dev59.com/QVfUa4cB1Zd3GeqPHmnF#6078812中的回答)。我的回答更多地涉及到与问题相关的方法,但实际上更好的方法是将其序列化为JSON。 - jhocking
这种语言太疯狂了。 - Aubergine

10
如何使用JSON模块?这样可以更好地交换数据。我通常喜欢使用dkjson,它还支持utf-8,而cmjjson则不支持。

1
点赞,因为让我意识到 JSON 是更好的解决方案。事实上,我在项目中已经使用了一个 JSON 库,但我忘记了。 - SomeCallMeTim

5

在Kong的工作原理下,它做了这件事。

local cjson = require "cjson"
kong.log.debug(cjson.encode(some_table))

需要安装lua-cjson包,可在https://github.com/openresty/lua-cjson/获取。


3
这是一个简单的程序,假设你的表格只包含数字。它输出Lua代码,可以使用loadstring()()加载回来。将其改为输出到字符串而不是打印出来。提示:重新定义print函数以将输出收集到表格中,然后在最后使用table.concat将输出表格转换为字符串。
t = {
{11,12,13},
{21,22,23},
}

print"return {"
for i=1,#t do
        print"{"
        for j=1,#t[i] do
                print(t[i][j],",")
        end
        print"},"
end
print"}"

3
假设:
  • 您没有循环(表a引用表b,表b引用表a)
  • 您的表是纯数组(所有键都是连续的正整数,从1开始)
  • 您的值仅为整数(没有字符串等)
那么递归解决方案很容易实现:
function serialize(t)
  local serializedValues = {}
  local value, serializedValue
  for i=1,#t do
    value = t[i]
    serializedValue = type(value)=='table' and serialize(value) or value
    table.insert(serializedValues, serializedValue)
  end
  return string.format("{ %s }", table.concat(serializedValues, ', ') )
end

在一个.lua文件中,将此函数生成的字符串前加上return,然后存储。
-- myfile.lua
return { { 1, 2, 3 }, { 4, 5, 6 } }

你可以直接使用dofile将表格取回。
t = dofile 'myfile.lua'

注:
  • 如果您有循环,那么通常需要使用额外的表格“跟踪”重复操作来显式处理它们。
  • 如果您没有纯数组,则需要以不同的方式解析 t,并处理键的呈现方式(它们是字符串吗?还是其他表格等)。
  • 如果您除了整数和子表之外还有其他内容,则计算 serializedValue 将更加复杂。
致敬!

2
我的解决方案:
local nl = string.char(10) -- newline
function serialize_list (tabl, indent)
    indent = indent and (indent.."  ") or ""
    local str = ''
    str = str .. indent.."{"
    for key, value in pairs (tabl) do
        local pr = (type(key)=="string") and ('["'..key..'"]=') or ""
        if type (value) == "table" then
            str = str..nl..pr..serialize_list (value, indent)..','
        elseif type (value) == "string" then
            str = str..nl..indent..pr..'"'..tostring(value)..'",'
        else
            str = str..nl..indent..pr..tostring(value)..','
        end
    end
    str = str:sub(1, #str-1) -- remove last symbol
    str = str..nl..indent.."}"
    return str
end

local str = serialize_list(tables)
print('return '..nl..str)

2

我有一个较短的代码可将表格转换为字符串,但无法反向转换

function compileTable(table)
   local index = 1
   local holder = "{"
   while true do
      if type(table[index]) == "function" then
         index = index + 1
      elseif type(table[index]) == "table" then
         holder = holder..compileTable(table[index])
      elseif type(table[index]) == "number" then
         holder = holder..tostring(table[index])
      elseif type(table[index]) == "string" then
         holder = holder.."\""..table[index].."\""
      elseif table[index] == nil then
         holder = holder.."nil"
      elseif type(table[index]) == "boolean" then
         holder = holder..(table[index] and "true" or "false")
      end
      if index + 1 > #table then
        break
      end
      holder = holder..","
      index = index + 1
   end
   return holder.."}"
end

如果你想改变名称,只需搜索所有的compileTable并将其更改为您首选的名称,因为如果检测到嵌套表但转义序列,则此函数将调用自身。我不知道它是否有效。
如果您使用此方法创建一个输出表的Lua可执行文件,并在其中放置新行和“序列”,则会出现编译错误。这种方法具有更高的内存效率。
注意:
1.不支持此功能
2.用户数据我不知道

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接