在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
lua序列化
使用示例 local t = { a = 1, b = 2} local g = { c = 3, d = 4, t} t.rt = g local ser_str = ser(g) local unser_table = loadstring(ser_str)()
原理详解采用递归序列化表的方式实现,并且支持循环引用。循环引用支持实现思路参考了云风的序列化. 直接使用 序列化keylocal keystr = nil if type(k) == "string" then keystr = string.format("[\"%s\"]", k) elseif type(k) == "number" then keystr = string.format("[%d]", k) end
序列化value
local valuestr = nil if type(v) == "string" then valuestr = string.format("\"%s\"", tostring(v)) elseif type(v) == "number" or type(v) == "boolean" then valuestr = tostring(v) elseif type(v) == "table" then valuestr = table_ser(v) end 分别处理完key和value直接插入一个表容器中就可以,最后在使用 在大字符串连接中,我们应避免 return string.format("{%s}", table.concat(container, ","))
精简后的代码
local function table_ser(tablevalue) -- 记录表中各项 local container = {} for k, v in pairs(tablevalue) do -- 序列化key local keystr = nil if type(k) == "string" then keystr = string.format("[\"%s\"]", k) elseif type(k) == "number" then keystr = string.format("[%d]", k) end -- 序列化value local valuestr = nil if type(v) == "string" then valuestr = string.format("\"%s\"", tostring(v)) elseif type(v) == "number" or type(v) == "boolean" then valuestr = tostring(v) elseif type(v) == "table" then valuestr = table_ser(v) end table.insert(container, string.format("%s=%s", keystr, valuestr)) end return string.format("{%s}", table.concat(container, ",")) end 支持循环引用其实普通序列化没什么好说的,重点在于对 使用一个表mark记录所有序列化过的表,并记录其全key(从根表到当前表的全路径key)每次新序列化一个表时,首先查看是否已经序列化过,若没有序列化则直接序列化, 若已经序列化过则处理如下: table序列化实现如下:
local function table_ser(tablevalue, tablekey, mark, assign) -- 标记当前table, 并记录其key名 mark[tablevalue] = tablekey -- 记录表中各项 local container = {} for k, v in pairs(tablevalue) do -- 序列化key local keystr = nil if type(k) == "string" then keystr = string.format("[\"%s\"]", k) elseif type(k) == "number" then keystr = string.format("[%d]", k) end -- 序列化value local valuestr = nil if type(v) == "string" then valuestr = string.format("\"%s\"", tostring(v)) elseif type(v) == "number" or type(v) == "boolean" then valuestr = tostring(v) elseif type(v) == "table" then -- 获得从根表到当前表项的完整key, tablekey(代表tablevalue的key), mark[v]代表table v的key local fullkey = string.format("%s%s", tablekey, keystr) if mark[v] then table.insert(assign, string.format("%s=%s", fullkey, mark[v])) else valuestr = table_ser(v, fullkey, mark, assign) end end if keystr and valuestr then local keyvaluestr = string.format("%s=%s", keystr, valuestr) table.insert(container, keyvaluestr) end end return string.format("{%s}", table.concat(container, ",")) end 调用table的序列化local function ser(var, enc) assert(type(var)=="table") -- 标记所有出现的table, 并记录其key, 用于处理循环引用 local mark = {} -- 用于记录循环引用的赋值语句 local assign = {} -- 序列化表, ret字符串必须与后面的loca ret=%s中的ret相同,因为这个ret可能也会组织到结果字符串中。 local ret = table_ser(var, "ret", mark, assign) local ret = string.format("local ret=%s %s return ret", ret, table.concat(assign, ";")) return (enc==nil or enc==true) and string.dump(loadstring(ret)) or ret end
mark:处理循环引用最重要的就是mark表,它记录了已经序列化的表和其完整key路径 序列化后就是一个lua的table创建并赋值的代码字符串,所以可以使用 序列化加密string.dump(loadstring(ret)) 这就是加密的代码,因为 完整代码见我github中的luaser |
请发表评论