segue dalla parte 9

stringhe e regular expression

in questa puntata apriremo una piccola digressione per analizzare le funzionalità del modulo string, in particolare l’uso delle regular expression.

Il modulo string ci mette a disposizione potenti funzioni di ricerca e sostituzione basate su espressioni regolari. Una completa implementazione delle regexp POSIX occuperebbe più dell’intero linguaggio, ma tutto sommato le funzionalità principali sono state mantenute, e gli autori di Lua sono riusciti a impacchettare un “motore” di pattern matching in meno di 500 righe di codice. Vediamone per sommi capi alcune caratteristiche: La funzione string.find(s,p) cerca un pattern p dentro la stringa s e ritorna una tupla di due valori: la posizione dove inizia la corrispondenza e quella dove finisce; in caso il pattern non sia presente, ritornerà nil.

>s=”hello moon”
>print(string.find(s,”bazinga”))
nil
>i,j=string.find(s,”hello”)
>print(i,j)
1 5
>print(string.sub(s,i,j))
hello

o, più concisamente, utilizzando la sintassi alternativa,

>print(s:sub(i,j))
hello

possiamo abbreviare la ricerca ed estrazione del testo con una sola chiamata:

>print(s:match(”hello”))
hello

la funzione di replace() richiede ovviamente un parametro in più; restituisce la nuova stringa e il numero di sostituzioni eseguite:

>k=”all your bases are belong to us”
>s,n=string.gsub(k,”s”,”z”)
>print(s,n)

il tutto diventa più interessante quando ricerchiamo o sostituiamo un pattern:

>p=”aiuole oltremisura”
>_,v=string.gsub(p,”[aeiou]”,””)
>print(“trovate”,v,”vocali”)

in questo caso scartiamo il primo valore ritornato assegnandolo a una variabile fittizia (underscore) perché ci serve solo il conteggio.

>html=[[<a href=”http://www.kernel.org”> <img src=”pinguino.gif”> </a>]]
>greedy=href=(.+)>
>lazy=href=(.-)>
>print(string.match(html,greedy)) -- non proprio quello che vogliamo
"http://www.kernel.org"> img src="pinguino.gif" </a 
>print(string.match(html,lazy))
"http://www.kernel.org" 

string.match ha anche l’equivalente string.gmatch che funziona come un iteratore. La sequenza di escape %b serve per il matching di testo racchiuso tra delimitatori. Quindi per tirare fuori tutti i tag da un html:

> for tag in string.gmatch(html,%b<>) print(tag) end

vale anche per gfind, ad esempio per implementare la classica funzione split() che suddivide le parole di un testo, che non è implementata nella libreria standard:

function split(s)
  local words={}
  for w in s:gfind(%a) do
    table.insert(words,w)
  end
  return words
end

per mostrare le potenzialità del meccanismo di ricerca e sostituzione scriviamo un convertitore di formato, che trasforma un comando in stile LaTex come \comando{testo libero} in XML testo libero:

>s=la nostra \quote{missione} è quasi \em{compiuta} 
>s=string.gsub(s, “\\(%a+){(.-)},<%1>%2</%1>)
>print(s)
la nostra <quote>missione</quote> è quasi <em>compiuta</em>

invece di un testo fisso o un pattern, possiamo passare a gsub una funzione, che riceve come input il testo cercato e restituisce la sostituzione. Esemplifichiamo questo concetto con una routine che decodifica gli URL encoding:

-- funzione ‘helper’ di appoggio
-- trasforma una coppia di cifre hex nel carattere corrispondente
function hextochar(n)
  return string.char(tonumber(n,16))
end

function unescape(url)
  url=string.gsub(url,'+',' ') -- trasforma + in spazi
  url=string.gsub(url,%%(%x%x), hextochar )  -- applica la funzione di trasformazione hex->char
  return url
end

>q=a%2Bb+%3D+c
>print(unescape(q))
a+b = c

prima di concludere, come ‘chicca’ finale segnalo un software : Lua-Quick-Try-Out

è un comodo ambiente di sviluppo interattivo dove scrivere ed eseguire comandi e script Lua, compresi esperimenti di grafica bitmap e vettoriale… Si scrive codice e si vede subito il risultato, in modo molto simile al basic dei primi homecomputer a 8bit!