Bienvenidos sean a este post, algunas veces necesitamos serializar algunos datos, pero que es serializar? Se considera serializar la accion de convertir los datos en un stream de bytes o caracteres, permitiendonos salvarlo en un archivo o enviarlo atraves de una conexion de red, en Lua tenemos la posibilidad de representar datos serializados como codigo de una manera que cuando corremos el codigo se reconstruye los valores grabados en el programa de lectura, cuando queremos restaurar el valor de una variable global nuestro chunk sera algo semejante a esto:

nombreVar = expresion
Anuncios

Donde expresion es el codigo Lua para crear el valor, nombreVar es la parte facil, veamos como escribir un codigo que crea un valor:

function serializar(o)
	if type(o) == "number" then
		io.write(o)
	else < otros casos >
	end
end

En este caso es solo para valores numericos y es bastante simple, donde si es de tipo number lo escribe de lo contrario evaluara otros casos, pero para cadenas necesitamos otro enfoque, una posibilidad de condicional podria ser el siguiente:

if type(o) == "string" then
	io.write("'", o, "'")

Sin embargo si la cadena contiene caracteres especiales (como comillas o un tabulador) el codigo resultante no sera un programa valido de Lua, una opcion podria ser:

if type(o) == "string" then
	io.write("[[", o, "]]")
Anuncios

Pero cuidado si un usuario malicioso se las ingenia para direccionar para grabar tu programa con algo similar a:

 ]] .. os.execute('rm *') .. [[ 

Daria como resultado el siguiente comando:

nombreVar = [[ ]] .. os.execute('rm *') .. [[ ]]

Obtendrias una desagradable sorpresa al intentar cargar estos “datos”, para evitar esto y poder encomillar de manera facil y segura una cadena es con la opcion “%q” de la funcion string.format, esta opcion rodeara con doble comillas y genera de forma correcta los modificadores de escape para los caracteres especiales, como pueden ser las comillas, la nueva linea, el tabulador, etc., dentro de la cadena como se ve en el siguiente ejemplo:

> a = 'a es una \\string "problematica"'
> print(string.format("%q",a))
"a es una \\string \"problematica\""
>
Anuncios

Aprovechando esta caracteristica podemos modificar a serializar de la siguiente forma:

function serializar(o)
	if type(o) == "number" then
		io.write(o)
	elseif type(o) == "string" then
		io.write(string.format("%q",o))
	else < otros casos >
	end
end

A partir de Lua 5.1 se ofrece otra opcion de encomillar cadenas arbitrarias de una forma segura con la nueva anotacion: [=[ … ]=] para cadenas largas, sin embargo su implementacion principal es para codigo escrito a mano donde no queremos cambiar ningun literal de ninguna forma, por esto en automatico es mas comodo, facil y rapido hacerlo por medio de %q de la funcion string.format. Sin embargo, si quieres usar la anotacion de cadena larga para codigo generado automaticamente, deberas tener cuidado en algunos detalles:

  • El numero correcto de signos iguales
  • Un valor correcto es siempre mayor al maximo existente en la cadena
  • Cadenas conteniendo largas cantidades de iguales no es poco comun (P.E. comentarios delimitando parte del codigo)
  • Podemos limitar nuestra atencion a secuencia de signos iguales precedidos por corchetes de cierre
  • El caracter nueva linea al comienzo de una de cadena larga es siempre ignoradp
  • Para evitar este problema siempre agrega al nueva linea al principio de la cadena
Anuncios

Veamos el siguiente codigo:

function quote(c)
	local n = -1
	for p in string.gmatch(c, "]==") do
		n = math.max(n, #p - 1)
	end
	local ig = string.rep("=", n + 1)
	return string.format(" [%s[\n%s]%s] ", ig, c, ig)
end

Este codigo es el resultado de observaciones anteriores, recibe una cadena arbitraria y lo devuelve formateado como una cadena larga, la llamada a string.gmatch crea un iterador para atravesar todas las ocurrencias del patron ‘]==’ (que es un corchete de cierre seguido por una secuencia de ceros o mas signos iguales) en la cadena c, por cada ocurrencia el bucle actualiza a n con el numero maximo de signos iguales hasta ahora, una vez terminado el bucle usamos string.rep para replicar un signo igual n veces mas uno, lo cual es una mas que lo ocurrido en la cadena para finalmente usar string.format encierra a c con pares de corchetes con el numero correcto de signos iguales entre medio y agrega espacios extras a las cadenas encomilladas y agregando una nueva linea al principio de la clase encerrada, probemos el codigo con la cadena a del ejemplo anterior:

> quote(a)
 [[
a es una \string "problematica"]]
>
Anuncios

En resumen, hoy hemos visto serializacion, su funcion, su practicidad, como aplicarlo, distintas formas de utilizarlo, espero les haya sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00