Bienvenidos sean a este post, hoy continuaremos con lo inciado en el post anterior y nos centraremos en dos ejemplos practicos donde primero veremos como usar la codificacion de URL y luego la expansion de pestañas, comencemos con el primer caso.

Anuncios

Codificacion URL

Esta es la codificacion usada por HTTP para enviar parametros en una URL (Localizador de recursos uniforme por sus siglas en ingles), esta codificacion codifica, perdon por la redundancia, caracteres especiaes (tales como ‘=’, ‘&’, ‘+’, etc) como ‘%xx’ donde xx es el valor hexadecimal del caracter, tambien cambia los espacios en signos de mas ‘+’, por ejemplo para codificar la cadena:

a+b = c 

Lo haria de la siguiente forma:

a+%2Bb+%3D+c
Anuncios

Para finalizar escribe cada nombre de parametro y valor de parametro con un signo igual (=) entre ellos y agrega todos los pares resultantes de nombre=valor con un ampersand (&) entre los mismos, por ejemplo los siguiente valores:

nombre = "martin"; query = "a+b = c"; q = "si o no"
Anuncios

Se codificaran de la siguiente forma:

nombre=martin&query=a%2Bb+%3D+c&q=si+o+no

Supongamos que queremos decodificar esta URL y almacenar cada valor en una tabla indexada por su correspondiente nombre, la siguiente funcion hace la decodificacion basica:

function unescape(s)
	s = string.gsub(s, "+", " ")
	s = string.gsub(s, "%%(%x%x)", function(h)
			return string.char(tonumber(h, 16))
		end)
	return s
end
Anuncios

La primera linea cambia todo los signos de mas (+) de la cadena en espacios, la segunda linea busca todos los valores hexadecimales de dos digitos precedidos por el signo de porcentaje (%) y llama a una funcion anonima para cada coincidencia, la funcion se encarga de convertir cada coincidencia encontrada en un numero con base 16 (hexadecimal) por medio de tonumber y luego con este valor por medio de string.char lo convierte en el caracter que corresponde, apliquems el siguiente ejemplo:

> print(unescape("a+%2B+b+%3D+c"))
a + b = c
Anuncios

Nuestro siguiente paso sera decodificar los pares de nombre = valor, para ello usaremos a string.gmatch porque tanto nombre como valores no pueden contener ni al ampersand (&) ni al signo igual (=), para ello podemos buscarlos por medio del patron ‘[^&=]+’ como se ve en la siguiente funcion:

cgi = {}
function decodificar(s)
	for nombre, valor in string.gmatch(s, "([^&=]+)=([^&=]+)") do
		nombre = unescape(nombre)
		valor = unescape(valor)
		cgi[nombre] = valor
	end
end
Anuncios

La llamada a string.gmatch busca todas las coincidencias con el par nombre=valor, por cada par el iterador devuelve la correspondiente captura (como se marca en el correspondiente parentesis en la cadena coincidente) como los valores para nombre y valor, el cuerpo del bucle solamente se dedica a aplicar lo visto anteriormente en unescape y almacenarlo en la tabla cgi, veamos un simple ejemplo:

> url="nombre=martin"
> decodificar(url)
> print(cgi.nombre)
martin
>
Anuncios

Para nuestro siguiente tema veremos como es codificar, algo bastante facil de hacer pero para ello debemos crear a funcion escape, esta funcion codifica todos los caracteres especiales como un “%” seguido por el codigo del caracter en hexadecimal (la opcion de formato “%02X” hace un valor hexadecimal con dos digitos usando 0 como relleno) y tambien cambia los espacios en signos de mas (+):

function escape(s)
	s = string.gsub(s, "[&=+%%%c]", function(c)
		return string.format("%%%02X", string.byte(c))
	end)
	s = string.gsub(s, " ", "+")
	return s
end
Anuncios

Para terminar con este tema vamos a ver la ultima funcion que es codificar, esta atraviesa toda la tabla construyendo la cadena resultante:

function codificar(t)
	local b = {}
	for k,v in pairs(t) do
		b[#b + 1] = (escape(k) .. "=" .. escape(v))
	end
	return table.concat(b, "&")
end
Anuncios

En este caso creamos un tabla local llamada b donde por medio de un bucle for obtendremos los valores de la tabla t y los asignaremos a k (clave) y v (valor), despues agregaremos a nuestra tabla local el valor de k concatenado con v y usamos a escape para codificar los caracteres especiales, unidos con el signo igual, por ultimo concatenaremos a la tabla b con el ampersand (&) y devolveremos el valor final, antes de probar nuestro programa veamos el codigo final del mismo:

urlencod.lua

function unescape(s)
	s = string.gsub(s, "+", " ")
	s = string.gsub(s, "%%(%x%x)", function(h)
			return string.char(tonumber(h, 16))
		end)
	return s
end

cgi = {}
function decodificar(s)
	for nombre, valor in string.gmatch(s, "([^&=]+)=([^&=]+)") do
		nombre = unescape(nombre)
		valor = unescape(valor)
		cgi[nombre] = valor
	end
end

function escape(s)
	s = string.gsub(s, "[&=+%%%c]", function(c)
		return string.format("%%%02X", string.byte(c))
	end)
	s = string.gsub(s, " ", "+")
	return s
end

function codificar(t)
	local b = {}
	for k,v in pairs(t) do
		b[#b + 1] = (escape(k) .. "=" .. escape(v))
	end
	return table.concat(b, "&")
end
Anuncios

Pasemos a probarlo de la siguiente forma:

Lua 5.3.3  Copyright (C) 1994-2016 Lua.org, PUC-Rio
> dofile("urlencod.lua")
> t = {nombre="martin", query="a + b = c", q="si o no"}
> t = codificar(t)
> print(t)
query=a+%2B+b+%3D+c&q=si+o+no&nombre=martin
> decodificar(t)
> print(cgi.nombre)
martin
> print(cgi.query)
a + b = c
> print(cgi.q)
si o no
Anuncios

Observen como creamos una tabla t con tres valores, luego lo codificamos, para luego imprimir el resultado, luego ejecutamos el decodificar sobre la cadena t, para imprimir los tres valores de cgi, estos se muestran correctamente, pasemos a la siguiente seccion.

Anuncios

Tabulacion

Una captura vacia como () tiene un significado especial en Lua, en lugar de capturar nada este patron captura su posicion en la cadena informada, y lo hace como un numero:

> print(string.match("Hola","()ol()"))
2       4
Anuncios

Podemos ver como el resultado no es el mismo que string.find porque la posicion de la segunda captura vacia es despues de la coincidencia, un buen ejemplo del uso de capturas vacias es para hacer una tabulacion en una cadena:

function tabulador(s, tab)
	tab = tab or 8
	local corr = 0
	s = string.gsub(s, "()\t", function(p)
		local sp = tab - (p - 1 + corr)%tab
		corr = corr -1 + sp
		return(string.rep(" ", sp))
	end)
	return s
end
Anuncios

El patron en string.gsub coincide con todos los tabs en la cadena, capturando sus posiciones, para cada tab la funcion interna usa esta posicion para computar el numero de espacios necesarios para arribar a una columna, ese es un multiplo de tab, substrae uno de la posicion para hacerlo relativo a cero y agrega a corr para compensar previos tabs, la expansion de cada tab afecta la posicion de los proximos, luego actualiza la correccion para ser usado por el proximo tab: menos uno para el tab que ha sido removido, ademas de sp para los espacios que estan siendo agregados, devuelve el numero apropiado de espacios, para completar mejor el concepto veamos como revertir esta operacion convirtiendo espacios en tabs, un primer enfoque podria envolver el uso de capturas vacias para manipular las posiciones pero hay una solucion mas simple, a cada octavo caracter le insertamos una marca en la cadena y cuando a marca es precedida por espacios lo reemplazamos con un tab:

function destabulador(s, tab)
	tab = tab or 8
	s = tabulador(s)
	local pat = string.rep(".", tab)
	s = string.gsub(s, pat, "%0\1")
	s = string.gsub(s, "+\1", "\t")
	s = string.gsub(s, "\1", "")
	return s
end
Anuncios

La funcion comienza expandiendo la cadena para remover cualquier tab previo, luego se computa un patron auxiliar para coincidir todas las secuencias de caracteres tab y usa este patron para agregar una marca (el caracter de control \1) despues de cada caracter tab, para luego sustituir un tab por todas las secuencias de espacios seguidos por una marca para finalmente remover las marcas que quedaron (las que no fueron procesadas por espacios).

Anuncios

En resumen, hoy hemos completado el tema de reemplazos, hemos visto como trabajar con la codificacion URL, tanto para codificarlo, como para decodificarlo, hemos visto como trabajar con capturas vacias, para que se usa, como gracias a esta crear un tabulador y destabulador, 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.

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00