Introduzione ai fogli di calcolo
L'argomento richiede l'estensione di argomenti già affrontati in precedenza. In particolare il concetto di sottoprocedura viene espeso in senso funzionale, cioè una sottoprocedura è una serie di operazioni che restituisce un valore. Un primo semplice esempio:
SOMMA(a, b)
{ return a+b }
è una sottoprocedura che restituisce ("return" è il termine che tradizionalmente si usa) la somma di a e di b. Quindi se troviamo in un programma x=SOMMA(3,7), x assumerà il valore 10. Si chiamano funzioni proprio perché è identico al concetto di funzione matematica.
Un esempio più verosimile (il + non è erto necessario metterlo in una funzione!) è la somma degli elementi di un vettore, che possono essere per esempio i movimenti di un conto bancario dei quali si può voler calcolare il totale. v è il generico vettore che contiene i valori da sommare (può essere anche quello delle carte da gioco ovviamente!), mentre n è il numero degli elementi da sommare:
SOMMA(v, n)
{
i=1
s=0
RIPETI FINCHE'(i<=n)
{
s = s+v[i]
i = i+1
}
return s
}
Come abbiamo già visto, dato che la memoria è unica all'interno di un programma, è concettualmente possibile riferirci direttamente alle locazioni di memoria, quindi potremmo definire una funzione del tutto simile alla precedente ma che invece di sommare gli elementi di un vettore somma i valori della memoria, da una certa posizione a un'altra posizione. La procedura, la cui modifica è piccolissima (con l'introduzine convenzionale del vettore MEMORIA che si riferisce all'intera memoria dle programma), diventa:
SOMMA(inizio, fine)
{
i=inizio
s=0
RIPETI FINCHE'(i<=fine)
{
s = s+MEMORIA[i]
i = i+1
}
return s
}
Come già discusso la memoria nella quale opera un programma si può considerare coma una striscia seminfinita di celle che contengono valori. Per comodità è possibile immaginare come se la memoria andasse "a capo" a un certo punto, diciamo per esempio dopo 100 celle (proprio come le pagine di Write) il nastro della memoria può essere spezzato e fatto continuare in basso. La numerazione rimane identica, quindi ogni cella può essere riferita sempre in base al suo ordine.
Ma dato che abbiamo trasformato il nastro unidimensionale in una "pagina" di locazioni bidimensionali, possiamo pensare di riferirci alle celle con le coordinate (come una matrice), la riga e la colonna. Ogni cella è identificata univocamente dalle sue coordinate, e ogni coppia di coordinate "lecite" identifica esattamente una cella.
Questa memoria, così organizzata, è esattamente quello che ci appare quando apriamo un programma di foglio di calcolo come "Calc" della suite OpenOffice sulla quale lavoriamo. Quello che ci appare è una prateria incontaminata di celle di memoria, dentro le quali possiamo inserire tutto quello che ci pare. Nei programmi di questo tipo normalmente le colonne vengono indicate dalle lettere dell'alfabeto, o da loro combinazioni (esercizietti: come descrivere le colonne quando superano la Z? Qual è l'ultima colonna di Calc? QUANTE sono in totale? -- IN DECIMALE!)
Lezione del 15 dicembre 2010 PSINFORM from Marco Tonti on Vimeo.
"L'informatica non riguarda i computer più di quanto l'astronomia riguardi i cannocchiali" (E. Dijkstra)
Blog del corso di Informatica del corso di laurea in Scienze e Tecniche Psicologiche, Università del Salento.
mercoledì 15 dicembre 2010
martedì 14 dicembre 2010
Variazione orario lezione
La lezione di domani mercoledì 15 dicembre comincerà alle 9 e terminerà alle 10.
domenica 12 dicembre 2010
Lezioni Prof.Valsiner
Le lezioni del prof.Valsiner saranno come sempre al CNOS, dalle 9 alle 19. Aula 15.
mercoledì 8 dicembre 2010
Lezione del 7 dicembre 2010
Lezione del 7 dicembre 2010 PSINFORM from Marco Tonti on Vimeo.
Espressioni regolari (note anche, e più brevemente, come RegEx da regular expressions. QUI per chi comprende l'inglese un sito eccellente ma non guardate in "about the site" per non prendere paura!, e QUI un sito dove fare prove)
Si tratta di un sistema quasi standard (con poche variazioni tra le varie implementazioni) per decrivere in modo più versatile le stringhe che si desidera cercare usando le comuni funzioni "cerca" di molti programmi di editor di testo, in particolare quello adottato dal nostro corso, Writer di OpenOffice. Per eseguire la ricerca nel modo standard è sufficiente aprire la finestra di ricerca e inserire la parola da cercare. Il "match", cioè la corrispondenza tra la paola cercata (in realtà una sequenza di caratteri) e i caratteri che compongono il testo, può essere vincolato in due modi: indicando che la parola trovata sia una parola intera (quindi "arco" non verrà trovato in "Marco" ma verrà trovato in "prese l'arco e centrò la mela": la punteggiatura è considerata un'interruzione di parola), o che la corrispondenza debba essere anche tra maiuscole e minuscole (quindi "Marco" verrebbe trovato in "Marco Tonti", ma non in "una moneta da un marco").
Le regex permettono di introdurre una varietà infinitamente più sofisticata nella modalità di descrizione di una stringa. Le RegEx (attivate in Writer nelle opzioni avanzate della ricerca) permettono per esempio di esprimere una stringa da cercare il cui matching può o meno comprendere un carattere, per esempio cercando "Marco?" (dove il "?" è un simbolo del linguaggio delle regex che indica che l'ultimo carattere può o meno essere presente) il programma troverebbe corrispondenze sia con "Marco Tonti" che con "Marc Chagall", perché abbiamo espresso nella ricerca l'informazione che la "o" finale può essere opzionale.
Un'altra possibilità che sarebbe utile è quella di poter indicare delle alternative che può avere un carattere in una certa posizione, per esempio se volessimo cercare (contemporaneamente) tutti i "Marco" e tutti i "Mario", potrebbe essere utile un modo per indicare che il quarto carattere possa essere sia una "c" che una "i". Nelle espressioni regolari per indicare una serie di scelte accetabili per un carattere si usano le parentesi quadre, all'interno delle quali inserire i caratteri accettabili in quella posizione, quindi se noi cercassimo "Mar[ic]o" esprimiamo il fatto che il quarto carattere può essere sia una "i" che una "c". Nelle parentesi quadre è possibile inserire anche cifre e intervalli, per esempio [a-z] indica tutti i caratteri dell'alfabeto (senza accentate, cifre ecc. solo le lettere). È possibile fare in modo che le quadre funzionino anche al contrario, cioè per indicare quali lettere NON devono essere presenti, questo lo si ottiene scrivendo [^ ] (oppure, in certe implementazioni, [! ]). Cercando "Mar[^c]io", potremmo trovare tutte le sequenze "Maraio", "Marbio", "mardio", "mareio"; notate però che "marcio" non è presente, perché imponiamo che in quella posizione NON possa esserci una "c" (e inoltre non siamo in Danimarca).
Esistono inoltre caratteri speciali che si usano come quantificatori. Uno l'abbiamo già introdotto ed è il "?", che significa che il carattere immediatamente precedente può comparire 0 o 1 volte. Per indicare che il carattere precedente può comparire da 0 a un numero indefinito di volte si usa il quantificatore *. Quindi se cercassimo "ab*c" il programma riconoscerebbe qualsiasi sequenza di composta di una "a" seguita da un qualsiasi numero di "b" e conclusa con una "c": "abc", "abbc", "abbbc", "abbbbc"... ma anche "ac" dove la "b" centrale compare 0 volte! Se vogliamo stringere il vincolo possiamo usare il quantificatore + che è molto simile al * ma impone che la sequenza sia lunga almeno un carattere. Scrivendo "ab+c" riconosceremmo "abc", "abbc", "abbbc" e così via ma non "ac". Lo stesso risultato lo potremmo ottenere con "abb*c", che si può leggere come: "una a seguita da una b seguita da una qualsiasi sequenza di b seguita da una c". La notazione col + però è più compatta e facile da leggere.
Provando a combinare gli elementi introdotti finora, cercando con la regex "[abc]+" otterremmo il riconoscimento di tutte le possibili sequenze di combinazioni dei caratteri a, b, c. Potremmo trovare "a", "b", "c", "aa", "ab", "ac", "ba", "bb", "bc", "ca", "cb", "cc", "aaa" e così via: qualsiasi combinazione di qualsiasi lunghezza dei caratteri a b c verrebbe riconosciuta, e SOLO quelle combinazioni verebbero riconosciute. "abcbaabababababacbcabcabcabcabcabacbcabccacbacbacacacbacbacbbcbcbcbbabcbcabbcbcbcbcabcbacb" sì, "aaaaaaaaa" sì, "bbbbbb" sì, "acab" sì, "bacca" sì, "ada" NO.
Un altro simbolo speciale è il carattere ".", il punto, che fa match con qualsiasi carattere (tranne gli a-capo). "a..b" troverebbe tutte le sequenza di 4 caratteri ai che cominciano con "a" e finiscono con "b". Toverebbe "acab", troverebbe "aaab", troverebbe "abbb". Anche questo carattere speciale può essere combinato con i quantificatori, quindi ".*" è una qualsiasi sequenza di caratteri.
Un altro carattere speciale è il "pipe": "|". Indica un'alternativa tra due espressioni regolari. Per esempio cercando "Marco|Mario" troveremmo tutte le occorrenze di Marco o di Mario. Notate che il | non agisce solo sui caratteri adiacenti, ma si espande a tutte le espressioni regolari verso sinistra e verso destra, quindi è necessario un modo per "contenere" la sua espansione. Per fare ciò in genere le scelte alternative si inseriscono tra parentesi tonde: (|). Le parentesi però hanno un ruolo tutt'altro che marginale nelle Regex, perché possono racchiudere qualsiasi tipo di espressione regolare e vengono considerate com un tutt'uno. Al quale si può applicare anche qualsiasi quantificatore. Per esempio (ab|cd)+ riconosce qualsiasi sequenza di caratteri composta di combinazioni qualsiasi delle sottosequenze "ab" o "cd". Riconoscerebbe "abcd", "cdab", "abababcdcdcd", "abcdabcdabcd". Ma NON "abcda", perché la sequenza si deve ottenere come iterazione di due possibili scelte "fisse": "ab" o "cd". Il quantificatore fa ripetere questa scelta per un numero indefinito di volte.
Riassumendo, i caratteri speciali che si usano nelle espressioni regolari sono:
[ ] un insieme di caratteri ammissibili per una posizione
[^ ] un insieme di caratteri NON ammissibili per una posizione
( ) una sotto-espressione regolare, gruppo
| un'alternativa tra due espressioni regolari
. un qualsiasi carattere
? quantificatore: 0 o 1 occorrenza del carattere (o gruppo) immediatamente precedente
* quantificatore: 0 o n occorrenze del carattere (o gruppo) immediatamente precedente
+ quantificatore: 1 o n occorrenze del carattere (o gruppo) immediatamente precedente
(ulteriori informazioni e approfondimenti si possono trovare ovunque cercando "espressioni regolari" con google, in particolare consiglierei: qui )
L'esempio che abbiamo affrontato a lezione è quello delle date. Le date (in linea di massima) hanno una struttura stabile e prevedibile, in particolare sono sequenze di due cifre, una barra, due cifre, una barra e quattro cifre. Se noi volessimo trovare tutte le date presenti in un documento (cioè tutte le sequenze di caratteri che rispondono a questo pattern) potremmo comodamente usare le espressioni regolari. Un primo approccio può essere il seguente (mettiamo di limitarci alle date del secolo scorso):
[0-9][0-9]/[0-9][0-9]/19[0-9][0-9]
però questa regex riconoscerebbe TUTTE le combinazioni fatte così, per cui anche eventuali sequenze di carattere (come dei codici) che date non sarebbero (riconoscerebbe 74/15/1999). Possiamo fare di meglio, restringendo per via sintattica la variabilità delle date. Intanto consideriamo che i numeri dei giorni possono andare da 01 a 31, quelli dei mesi da 01 a 12. Adeguiamo le descrizioni a questi nuovi vincoli:
[0-3][0-9]/[01][0-9]/19[0-9][0-9]
Anche in questo caso esistono sequenze che possono essere trovate ma che non sono date, per esmepio 39/19/1999. Si può fare di meglio? Certo! Bisogna considerare che certe combinazioni di valori, in particolare i valori dei giorni che cominciano con 3 e dei mesi che cominciano con 1, non sono tutte accettabili e possono essere escluse a priori. Dato che dobbiamo distinguere due casi sia per i giorni che per i mesi, bisogna usare un operatore di | che ci faccia stabilire in quale dei due casi ci troviamo, ricordandosi di raggrupparli in parentesi.
(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012])/19[0-9][0-9]
Analizziamo la sottoespressione dei giorni: 0[1-9]|[12][0-9]|3[01]
Questa espressione ci pone davanti a tre alternative per il riconoscimento: o la stringa che stiamo cercando comincia con uno 0 (e allora può essere seguta solo da un numero tra 1 e 9: il giorno 00 non esiste), oppure la stringa comincia con un 1 o con un 2 (e allora può essere seguita da qualsiasi cifra), o comincia con un 3 (e allora può essere seguita solo da uno 0 o da un 1). Questa espressione riconosce solo ed esattamente le sequenze di due caratteri che rappresentano numeri compresi tra 01 e 31.
L'espressione dei mesi è analoga: 0[1-9]|1[012]
Se la sequenza comincia con uno 0 allora la cifra dopo dev'essere compresa tra 1 e 9, se comincia con 1 allora può essere seguita solo da 0, 1, 2.
Notate che alcune date sfuggono comuque, ma sono vincoli di natura semantica difficilmente traducibili in sintassi: verrebbe riconosciuta come data anche il 31/02/1999 o il 31/08/1999 (ma febbraio ha al massimo 29 giorni e agosto ne ha 30, quindi queste non sono veramente date). Dopo aver fatto la lezione e dopo aver scritto questo riassunto, guardando sul sito che vi ho segnalato ho trovato questo: http://www.regular-expressions.info/dates.html praticamente le stesse cose che ho descritto qui.
Nei fatti pratici raramente è utile descrivere le date in tanto dettaglio, ma la tecnica è talmente versatile da poter essere usata per esempio per trovare (o verificare) indirizzi email:
[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}
Per comprendere come mai questa espressione è in grado di riconoscere un'email, bisogna aggiungere un dettaglio sull'ultima espressione fra graffe: è un modo per quantificare apertamente una ripetizione, e significa: il carattere precedente ripetuto da 2 a 4 volte (che cattura per esempio i ".it" o ".com" o ".info"). Per collegarlo a quanto detto prima, il quantificatore ? corisponde esattamente a {0,1}. Inoltre l'ultimo "." della regex non è un carattere speciale, perché essendo preceduto da una \ il sistema sa che lo deve trattare come un "letterale" e non come un carattere del linguaggio. Quindi nella sintassi delle regex \. fa match con un "." nel testo, mentre . fa match con qualsiasi carattere.
Per trovare la spiegazione, guardate qui con tutti i dettagli illustrati ottimamente.
Ciò detto sulla ricerca, e trovato il modo per individuare una generica data, potremmo chiederci che possiamo farcene. Mettiamo di voler trasformare tutte le date espresse all'italiana come abbiamovisto nel formato internazionale: anno-mese-giorno. Se ci fate caso, le informazioni necessarie noi le possiamo già "catturare" con la regex delle date che abbiamo costruito: basterebbe prendere i pezzi e riordinarli diversamente. Questo è possibile farlo usando i gruppi, cioè le parentesi tonde. Tutto ciò che viene a trovarsi tra parentesi tonde è un gruppo, e il sistema che si usa lo memorizza permettendoci di riutilizzarlo nella casella SOSTITUISCI. I gruppi sono identificati con la loro posizione della regex partendo da sinistra, quindi il primo gruppo a sinistra ha il numero 1, il secondo il numero 2 e così via. Per riferirci a loro nella casella "sostituisci" usiamo il $, $1 è quello che è stato trovato nel primo gruppo, $2 il secondo e così via.
Riscriviamo la nostra espressione per catturare anche il contenuto dell'anno:
(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012])/(19[0-9][0-9])
Se noi inseriamo questo in "cerca", e in trova invece inseriamo
$3-$2-$1
Quando clicchiamo "sostituisci tutto" (come si vede nel filmato) il programma effettuerà in modo completamente automatico questo lavoro. Istantaneamente. Gli stiamo di fatto chiedendo: TROVA nel testo una combinazione di caratteri che risponda alla nostra descrizione, e memorizza i caratteri che ricadono nelle posizioni avvolte da parentesi, quindi SOSTITUISCI tutto quello che hai trovato e che hai riconosciuto come data, con la nuova sequenza di caratteri che ottieni prendendo i caratteri che ricadono nel terzo gruppo, seguito da un -, poi il contenuto del secondo gruppo, seguito da un -, poi il contenuto del primo gruppo. In questo modo la sequenza trovata viene ineramente sostituita da una nuova sequenza costruita "al volo" e che varia in base alla stringa riconosciuta. Avremmo ovviamente potuto sostituire qualsiasi cosa alle date, per esmepio delle "xxx" per rimuovere ogni riferimento temporale dal testo! Oppure sostituire la data con $1/$2 per eliminare l'informazione dell'anno.
Un ultimo elemento introdotto a lezione che permette di aggiungere vincoli alle espressioni regolari sono i segnaposti per inizio e fine del paragrafo. Se vogliamo catturare solo le date (o le etichette, come si vede anche nel filmato) che si trovano esattamente all'inizio della riga, è sufficiente inserire un carattere ^ all'inizio della regex: ^(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012])/(19[0-9][0-9]) , questo impone il vincolo che non solo la sequenza deve essere trovata, ma deve trovarsi adiacente all'inizio della riga (se vogliamo riconoscere solo date che partono dalla quinta posizione possiamo sempre fare ^....(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012])/(19[0-9][0-9]) cioè, dato che il punto è un carattere qualsiasi, partendo da inizio riga contiamo quattro caratteri non meglio specificati, e lì cerchiamo la data.
Un'altra applicazione di cui si è discusso è la rimozione degli spazi vuoti ripetuti in un testo: è sufficiente cercare " +" (uno spazio, seguito da un +) e sostituirlo con uno spazio singolo " ". Per formattare correttamente la punteggiatura è sufficiente usare un gruppo di cattura (tra parentesi quadre il punto è solo un punto, non rappresenta un carattere speciale):
cerca: " *([,.;:]) *"
sosstituisci: "$1 "
In pratica cerca un segno di punteggiatura preceduto e seguito da 0 o più spazi (i vari casi possono essere "ciao,amico" "ciao , amico" "ciao ,amico" "ciao ,amico" "ciao , amico" ecc.). Dato che l'elemento di punteggiatura è registrato in un gruppo di cattura, nel "sostituisci" possiamo utilizzaro per rimpiazzarlo a se stesso, ma circondato dagli spazi giusti: "ciao, amico".
martedì 7 dicembre 2010
Lezione del 6 dicembre 2010
Lezione del 6 dicembre 2010 PSINFORM from Marco Tonti on Vimeo.
Argomenti della lezione (per un disguido niente audio mi spiace) su OpenOffice Writer:
- Inserimento di interruzioni manuali di pagina
- Margini di paragrafo o dela prima riga del paragrafo
- Stili di paragrafo
- Tabulazioni personali (sinistre, centrate, destre e decimali)
- Inserimento note a piè di pagina
- Inserimento numeri di pagina (ed esclusione dalla prima pagina dalla numerazione, con esempio di ricerca con Google)
- Tabelle
- Esportazione in PDF
- Scorciatoie di tastiera per il copia-incolla (CTRL-C CTRL-V)
- Sistema delle revisioni (memorizzazione dei cambiamenti)
- Ricerca e sostituzione avanzata
- Primi cenni di espressioni regolari
lunedì 6 dicembre 2010
Aggiornamento calendario lezioni
Le lezioni del 9, 13 e 14 dicembre non ci saranno, per via delle lezioni intensive dei prof. Rosa e Valsiner. Le altre lezioni avranno luogo normalmente.
QUESTION TIME
Inserite nei commenti a questo post domande, questioni o argomenti su cose che vi interesserebbe approfondire o cose che non vi sono chiare (anche al di fuori del programma del corso). Cercherò di fare una sintesi di dedicare una lezione alle vostre richieste.
Iscriviti a:
Post (Atom)