校园超市网站开发,365建设网站,可以做婚礼鲜花布置的网站,上海网站建设推荐q479185700顶你我们经常需要序列化一些数据#xff0c;为了将数据转换为字节流或者字符流#xff0c;这样我们就可以保存到文件或者通过网络发送出去。我们可以在 Lua 代码中描述序列化的数据#xff0c;在这种方式下#xff0c;我们运行读取程序即可从代码中构造出保存的值。
number/st…我们经常需要序列化一些数据为了将数据转换为字节流或者字符流这样我们就可以保存到文件或者通过网络发送出去。我们可以在 Lua 代码中描述序列化的数据在这种方式下我们运行读取程序即可从代码中构造出保存的值。
number/string
对于number和string类型其实非常好序列化number类型就直接返回其本身即可
if type(o) number thenreturn o
end
string类型需要专门处理有一个正则匹配是%q是一种字符串格式化表达式为了防止类似os.execute(rm *)的注入式攻击所以采用这种匹配形式来完成string的序列化
if type(o) number thenreturn string.format(%q,o)
end 若采用类似于([[, o, ]])的形式来实现序列化那么如果输入是 ]]..os.execute(rm *)..[[ 最后拼接结果则是[[ ]]..os.execute(rm *)..[[ ]]load之后则会出现严重的后果。 table
{[b] Lua,[a] 12,[key] {[b] 4,[a] 3,},1 2,
}
如果是table类型如果按照以上形式来呈现序列化效果则需要注意嵌套table和缩进格式。
function serialize(o,strPrefix)strPrefix strPrefix or if type(o) number thenreturn oelseif type(o) string thenreturn string.format(%q,o)elseif type(o) table thenlocal result {\nfor k,v in pairs(o) dolocal strFormat %sif type(k) string thenstrFormat [\%s\]endresult result..strPrefix..\t..string.format(strFormat,k).. ..serialize(v,strPrefix..\t)..,\nendresult result..strPrefix..}return resultelse error(cannot serialize a .. type(o)) end
end
通过pairs循环来对key value值一个个序列化其中strFormat指的是如果key的类型是string才需要加上【】以确保正确序列化key值。如果是嵌套table则需要注意递归序列化传入这个新的table和缩进用以保证正常的序列化输出。于是输入和输出如下
local tb
{[a] 12, [b] Lua, [1] 2,[key] {[a] 3,[b] 4,}
}
print(serialize(tb))
{[b] Lua,[a] 12,[key] {[b] 4,[a] 3,},[1] 2,
}
如果看programming in lua原文其实大差不差只是原文没有缩进格式的优化。
循环table
如果出现循环引用table的形式那么整个问题将会变得比较复杂一点比如:
local a {}
a.c 1
a.z a
由此可以在之前的基础上做一个优化缓存table map。意指当我们遍历里面的key值发现其中仍然有序列化之前已经被序列化的table则做特殊处理
local tableMap {} --用以保存已经被序列化的table
local tbKeyToTableSerialize {} --用以保存那些引用了table本身的key的序列化stringfunction serialize(o,strPrefix)strPrefix strPrefix or --string前缀用来正确显示缩进if type(o) number thenreturn oelseif type(o) string thenreturn string.format(%q,o)elseif type(o) table thenlocal result {\n--如果自身是table则第一时间加入表中tableMap[o] o.namefor k,v in pairs(o) dolocal strFormat [%s]if type(k) string thenstrFormat [\%s\]endif type(v) table then--如果是tablemap没有的则正常序列化并且存进mapif not tableMap[v] thenresult result..strPrefix..\t..string.format(strFormat,k).. ..serialize(v,strPrefix..\t)..,\nelse--否则直接添加到序列化string中之后直接输出即可table.insert(tbKeyToTableSerialize,o.name.....k.. ..tableMap[v])endelseresult result..strPrefix..\t..string.format(strFormat,k).. ..serialize(v,strPrefix..\t)..,\nendendresult result..strPrefix..}return resultelse error(cannot serialize a .. type(o)) end
endfunction serializeAll(o)print(o.name.. ..serialize(o))for i 1,#tbKeyToTableSerialize doprint(tbKeyToTableSerialize[i])endtbKeyToTableSerialize {}tableMap {}
end
最终测试代码和测试结果
local a {}
a.name a
a.z a
a.x {}
a.x.name a.x
a.x.y a
a.x.x a.x
serializeAll(a)
a {[x] {[name] a.x,},[name] a,
}
a.z a
a.x.y a
a.x.x a.x
当然这里的name只是我这边显式添加的value值实际上可以setmetatable里面复写index来达成条件但依然是不知道具体table名的。
官方文档相比以上会更激进一些其直接换成了另一个输出格式
a {}
a[1] {}
a[1][1] one
a[1][2] two
a[2] 3
b {}
b[k] a[1]