lua-users home
lua-l archive

persistent data & serialization

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hello,
I've seen the thread about serialization earlier in this list,
but didn't find the code mentioned there.
To deal with persistent data in LUA similar to the Win95 INI-Files, I put
together a serialization scheme for basic lua types (Lua version 3.2).
'function' and 'userdata' is not supported.
There is one function 'serialize(t,q)' which returns a _one_ line 
representation of the value of variable t. Parameter q is optional to 
change the default quote character (') of string serialization.
Note that the name of the serialized variable is not included in
the serial representation but only the value.
The other function is 'unserialize(s)' which tries to undo what 
serialize did. It's also possible to unserialize unquoted strings, but 
this can have side effects. Look at attached source for details.
To see an example of how it works, run 
$lua serial.lua >out 
from the command line and look at the generated output in file 'out'.
It's not heavily tested but works fine for me. 
May be it is useful for someone else.
Comments, improvements and bug reports are welcome.
CM
-- 
Sent through GMX FreeMail - http://www.gmx.net 
-----------------------------------------------------------------------------
-- Simple serialization of basic lua types
-- 11/12/2000 Christof Muz
-- This is public domain. Absolutely no guarantees.
-----------------------------------------------------------------------------
-----------------------------------
-- Make a _flat_ copy of table t --
-----------------------------------
function duptable(t)
if type(t) == 'table' then
 local nt = {}
 local i,v = next(t,nil)
 while i do
 nt[i]=v
 i,v = next(t,i)
 end
 return nt
end
return t
end
---------------------------------------------
-- Escape all special characters of string --
---------------------------------------------
function escapestring(s)
 s = gsub(s,"([%c\\'\"%z]?)", -- convert special characters
	 function(l)
	 if l and l ~= '' then
		if strbyte(l) == strbyte('\n') then return "\\n" end
		if strbyte(l) == strbyte('\t') then return "\\t" end
		if strbyte(l) == strbyte('\r') then return "\\r" end
		if strbyte(l) == strbyte('\f') then return "\\f" end
		if strbyte(l) == strbyte('\\') then return "\\\\" end
		if strbyte(l) == strbyte('"') then return '\\"' end
		if strbyte(l) == strbyte("'") then return "\\'" end
		return "\\" .. tonumber(strbyte(l))
	 end
	 end
	 )
 return s
end
----------------------------------------------------
-- Serialize a luatype (recursively for 'tables') --
-----------------------------------------------------------------------------
-- The serialization of a luatype is a _one_ line string (e.g. no \n,...)
-- ot : the luatype , works fine with 'table', 'string', 'number' and nil
--	for userdata and functions the type string is returned.
-- q (optional) : quote-character for string serialization (default is "'")
-----------------------------------------------------------------------------
function serialize(ot,q)
 if ot == nil or
 type(ot) == 'number' then
 return tostring(ot)
 end
 if not q then -- string quotation character
 q = "'"
 end
 if type(ot) == 'string' then
 ot = escapestring(ot)
 return q .. ot .. q
 end
 if type(ot) == 'table' then -- tables
 local s ='{' -- serial representation to build
 local t = duptable(ot) -- work on a copy of the table
 local i,n = 1,getn(t) -- iteration start for 'array' elements
 local sep = '' -- the item seperator for output
 local defd = '_$visited$_' -- this element is already serialized
 while i<=n do 	 -- first all array items
 if t[i] then s = s .. sep .. serialize(t[i]) end
 t[i]=defd
 sep = ','
 i=i+1
 end
 sep=';'
 i,v = next(t,nil)	-- iterate again for all other items
 while i do
 if v and v ~= defd then
 s = s .. sep .. tostring(i) .. '=' .. serialize(v)
 sep=','
 end
 i,v = next(t,i)
 end
 s = s .. '}'
 return s
 end
 return q .. type(ot) .. q
end
------------------------
-- Undo serialization --
-----------------------------------------------------------------------------
-- only type 'string' is considered a valid serialization
-- other types are simply returned !
-- serialized strings should be quoted (e.g "'a string'"), which
-- is the default behaviour of serialize.
-- If not quoted the default 'tonumber' conversion may lead to
-- unexpected results. ( e.g. string(1stclass) -> number(1) )
-- Leading whitespace is _NOT_ stripped, which might be a problem with
-- 'table' unserialization, as tables are identified by a '{'-character
-- at the first position. (e.g. string({n=0}) -> table {n=0}
-- but string( {n=0}) represents a string
--	 ^ space-character
-----------------------------------------------------------------------------
function unserialize(s)
if type(s) ~= 'string' then return s end
if tonumber(s) then return tonumber(s) end -- seems to be a simple number
					 -- but watch out: '1a-class'
if s == tostring(nil) then return nil end -- nil
if strbyte(s) ~= strbyte('{') and -- not a tabledef string
 strbyte(s) ~= strbyte("'") and -- and
 strbyte(s) ~= strbyte('"') then -- not a quoted string
 local t = escapestring(s)
 s = "'" .. t .. "'" -- quote the string
end
 local gname = '__unserialized__var'
 local t
 -- parse string with lua core
 dostring(gname.."="..s) -- convert it
 t = getglobal(gname)
 setglobal(gname,nil)
 return t
end
-----------------------------------------------------------------------------
-- Tests of serialization/unserialization
-----------------------------------------------------------------------------
function xforeach(t,f,l) -- recursively for tables
local i,v = next(t,nil)
 if not l then l=0 end
 while i do
 if type(v) == 'table' then
 f(l,i,v)
 xforeach(v,f,l+1)
 else
 f(l,i,v)
 end
 i,v = next(t,i)
 end
end
function tp(l,n,v) -- print table hierarchy (l=level)
local s=''
 while l > 0 do s=s..'\t' l=l-1 end
 print(format("%s[%s]=(%s)%s",s,n,type(v),tostring(v)))
end
-----------------------------------------------------------------------------
--- define test data
-----------------------------------------------------------------------------
tab = {1,2,3,4,
 {5.1,5.2;n=2,t='subtable'},
 {6.1,6.2;n=2,t='subtable'};
 n=6,
 example='table serialization'}
strtab = { " 'first' ",' "second" ', " \"third\" ",' \'fourth\' '}
bindat = [[Hello World
from Lua
This is a longer 'string' with

 embedded ctrl-characters\t
]]
thetest = {tab,strtab,bindat;n=3}
-----------------------------------------------------------------------------
-- The test
-----------------------------------------------------------------------------
--- print test data
print('test data:')
xforeach(thetest,tp)
--- serialize and print serialization
thetestser = serialize(thetest)
print('\nserial representation of test data:')
print(thetestser,"\n")
--- unserialize and print generated data
print('unserialized test data:')
xforeach(unserialize(thetestser),tp)

AltStyle によって変換されたページ (->オリジナル) /