Chapter 9 Esercitazione: Giochi con le paroleQuesto capitolo contiene la seconda esercitazione, in cui dovrete risolvere dei quesiti che consistono nel ricercare parole che hanno delle particolari proprietà. Ad esempio, cercherete i più lunghi palindromi della lingua inglese e le parole le cui lettere sono disposte in ordine alfabetico. Illustrerò anche un’altra tecnica di sviluppo: la riduzione ad un problema già risolto. 9.1 Leggere elenchi di parolePer gli esercizi di questo capitolo ci serve un elenco di parole in inglese. Ci sono parecchi elenchi di parole disponibili sul Web, ma uno dei più adatti ai nostri scopi è quello raccolto da Grady Ward, di pubblico dominio, parte del progetto lessicale Moby (vedere http://wikipedia.org/wiki/Moby_Project). È un elenco di 113.809 parole ufficiali per cruciverba, cioè parole che sono considerate valide in un gioco di parole crociate o altri giochi con le parole. Nella raccolta Moby il nome del file è 113809of.fic; potete anche scaricare una copia chiamata più semplicemente words.txt, dal sito http://thinkpython2.com/code/words.txt. Il file è in testo semplice, e potete aprirlo con qualsiasi editor di testo, ma anche leggerlo con Python: la funzione predefinita open richiede come parametro il nome di un file e restituisce un oggetto file che potete utilizzare per questo scopo. >>> fin = open('words.txt') fin è un nome comunemente usato per un oggetto file usato per operazioni di input. L’oggetto file comprende alcuni metodi di lettura, come readline, che legge i caratteri da un file finché non giunge ad un ritorno a capo, e restituisce il risultato sotto forma di stringa: >>> fin.readline() 'aa\r\n' La prima parola di questa speciale lista è “aa”, che è un tipo di lava vulcanica. La sequenza L’oggetto file tiene traccia del punto in cui si trova all’interno del file, così quando chiamate nuovamente readline, ottenete la parola successiva: >>> fin.readline() 'aah\r\n' La parola successiva è “aah”, che è perfettamente valida per cui non fate quella faccia! Oppure, se gli spaziatori vi danno fastidio, potete sbarazzarvene con il metodo delle stringhe strip: >>> riga = fin.readline() >>> parola = riga.strip() >>> parola 'aahed' Potete anche usare un oggetto file all’interno di un ciclo for. Questo programma legge words.txt e stampa ogni parola, una per riga: fin = open('words.txt') for riga in fin: parola = riga.strip() print(parola) 9.2 EserciziLe soluzioni a questi esercizi sono discusse nel prossimo paragrafo. Tentate almeno di risolverli prima di continuare la lettura.
Esercizio 1 Scrivete un programma che legga il file words.txt e stampi solo le parole composte da più di 20 caratteri (caratteri spaziatori esclusi).
Esercizio 2 Nel 1939, Ernest Vincent Wright pubblicò una novella di 50.000 parole dal titolo Gadsby che non conteneva alcuna lettera “e”. Dato che la “e” è la lettera più comune nella lingua inglese, non è una cosa facile. Infatti, in italiano non ho mai composto un piccolo brano siffatto: sono pochi i vocaboli privi tali da riuscirci; finora non ho trovato alcun modo, ma conto di arrivarci in alcuni giorni, pur con un po’ di difficoltà! Ma ora, basta così. Scrivete una funzione di nome Modificate il programma del paragrafo precedente in modo che stampi solo le parole dell’elenco prive della lettera “e”, e ne calcoli la percentuale sul totale delle parole.
Esercizio 3 Scrivete una funzione di nome evita che richieda una parola e una stringa di lettere vietate, e restituisca True se la parola non contiene alcuna lettera vietata. Modificate poi il programma in modo che chieda all’utente di inserire una stringa di lettere vietate, e poi stampi il numero di parole che non ne contengono alcuna. Riuscite a trovare una combinazione di 5 lettere vietate che escluda il più piccolo numero di parole?
Esercizio 4 Scrivete una funzione di nome
Esercizio 5 Scrivete una funzione di nome
Esercizio 6
Scrivete una funzione di nome 9.3 RicercaTutti gli esercizi del paragrafo precedente hanno qualcosa in comune: possono essere risolti con lo schema di ricerca che abbiamo visto nel Paragrafo 8.6. L’esempio più semplice è: def niente_e(parola): for lettera in parola: if lettera == 'e': return False return True Il ciclo for attraversa i caratteri in parola. Se trova la lettera “e”, può immediatamente restituire False; altrimenti deve esaminare la lettera seguente. Se il ciclo termina normalmente, vuol dire che non è stata trovata alcuna “e”, per cui il risultato è True. Si potrebbe scrivere questa funzione in modo più conciso usando l’operatore in, ma ho preferito iniziare con questa versione perché dimostra la logica dello schema di ricerca. evita è una versione più generale di def evita(parola, vietate): for lettera in parola: if lettera in vietate: return False return True Possiamo restituire False appena troviamo una delle lettere vietate; se arriviamo alla fine del ciclo, viene restituito True.
def usa_solo(parola, valide): for lettera in parola: if lettera not in valide: return False return True Invece di un elenco di lettere vietate, ne abbiamo uno di lettere disponibili. Se in parola troviamo una lettera che non è una di quelle valide, possiamo restituire False.
def usa_tutte(parola, richieste): for lettera in richieste: if lettera not in parola: return False return True Invece di attraversare le lettere in parola, il ciclo attraversa le lettere richieste. Se una qualsiasi delle lettere richieste non compare nella parola, restituiamo False. Ma se avete pensato davvero da informatici, avrete riconosciuto che def usa_tutte(parola, richieste): return usa_solo(richieste, parola) Ecco un esempio di metodo di sviluppo di un programma chiamato riduzione ad un problema già risolto, che significa che avete riconosciuto che il problema su cui state lavorando è un’istanza di un problema già risolto in precedenza, al quale potete applicare una soluzione che avevate già sviluppato. 9.4 Cicli con gli indiciHo scritto le funzioni del paragrafo precedente utilizzando dei cicli for perché avevo bisogno solo dei caratteri nelle stringhe e non dovevo fare nulla con gli indici. Per def alfabetica(parola): precedente = parola[0] for c in parola: if c < precedente: return False precedente = c return True Un’alternativa è usare la ricorsione: def alfabetica(parola): if len(parola) <= 1: return True if parola[0] > parola[1]: return False return alfabetica(parola[1:]) E un’altra opzione è usare un ciclo while: def alfabetica(parola): i = 0 while i < len(parola)-1: if parola[i+1] < parola[i]: return False i = i+1 return True Il ciclo comincia da i=0 e finisce a i=len(parola)-1. Ogni volta che viene eseguito, il ciclo confronta l’ i-esimo carattere (consideratelo come il carattere attuale) con l’ i+1-esimo carattere (consideratelo come quello successivo). Se il carattere successivo è minore di quello attuale (cioè viene alfabeticamente prima), allora abbiamo scoperto un’interruzione nella serie alfabetica e la funzione restituisce False. Se arriviamo a fine ciclo senza trovare difetti, la parola ha superato il test. Per convincervi che il ciclo è terminato correttamente, prendete un esempio come Ecco una variante di def palindromo(parola): i = 0 j = len(parola)-1 while i<j: if parola[i] != parola[j]: return False i = i+1 j = j-1 return True Oppure, possiamo ridurre ad un problema già risolto e scrivere: def palindromo(parola): return al_contrario(parola, parola) Usando 9.5 DebugCollaudare i programmi non è facile. Le funzioni di questo capitolo sono relativamente agevoli da provare, perché potete facilmente controllare il risultato da voi. Nonostante ciò, scegliere un insieme di parole che riescano a escludere ogni possibile errore è un qualcosa tra il difficile e l’impossibile. Prendiamo ad esempio Per ciascun caso ci sono alcuni sottocasi meno ovvi. Tra le parole che contengono “e”, dovreste provare parole che iniziano con “e”, finiscono con “e”, hanno “e” da qualche parte nel mezzo della parola. Dovreste poi provare parole lunghe, parole corte e parole cortissime. Nello specifico, la stringa vuota è un esempio di caso particolare, che è uno dei casi meno ovvi dove si nascondono spesso gli errori. Oltre che con i casi da voi ideati, sarebbe anche bene fare un test del vostro programma con un elenco di parole come words.txt. Scansionando l’output potreste intercettare qualche errore, ma attenzione: può trattarsi di un certo tipo di errore (parole che non dovrebbero essere incluse ma invece ci sono) e non di un altro (parole che dovrebbero essere incluse ma non ci sono). In linea generale, fare dei test può aiutarvi a trovare i bug, ma non è facile generare un buon insieme di casi di prova, e anche se ci riuscite non potete essere certi che il vostro programma sia corretto al 100 per cento. Secondo un leggendario informatico: Il test di un programma può essere usato per dimostrare la presenza di bug, ma mai per dimostrarne l’assenza! 9.6 Glossario
9.7 EserciziEsercizio 7
Questa domanda deriva da un quesito trasmesso nel programma radiofonico Car Talk (http://www.cartalk.com/content/puzzlers): “Ditemi una parola inglese con tre lettere doppie consecutive. Vi dò un paio di parole che andrebbero quasi bene, ma non del tutto. Per esempio la parola “committee”, c-o-m-m-i-t-t-e-e. Sarebbe buona se non fosse per la “i” che si insinua in mezzo. O “Mississippi”: M-i-s-s-i-s-s-i-p-p-i. Togliendo le “i” andrebbe bene. Ma esiste una parola che ha tre coppie di lettere uguali consecutive, e per quanto ne so dovrebbe essere l’unica. Magari ce ne sono altre 500, ma me ne viene in mente solo una. Qual è?” Scrivete un programma per trovare la parola. Soluzione: http://thinkpython2.com/code/cartalk1.py.
Esercizio 8
Ecco un altro quesito di Car Talk
(http://www.cartalk.com/content/puzzlers):
“L’altro giorno stavo guidando in autostrada e guardai il mio contachilometri. È a sei cifre, come la maggior parte dei contachilometri, e mostra solo chilometri interi. Se la mia macchina, per esempio, avesse 300.000 km, vedrei 3-0-0-0-0-0.” Scrivete un programma in Python che controlli tutti i numeri a sei cifre e visualizzi i numeri che soddisfano le condizioni sopra indicate. Soluzione: http://thinkpython2.com/code/cartalk2.py.
Esercizio 9
Ecco un altro quesito di Car Talk (http://www.cartalk.com/content/puzzlers) che potete risolvere con una ricerca :
“Di recente ho fatto visita a mia madre, e ci siamo accorti che le due cifre che compongono la mia età, invertite, formano la sua. Per esempio, se lei avesse 73 anni, io ne avrei 37. Ci siamo domandati quanto spesso succedesse questo negli anni, ma poi abbiamo divagato su altri discorsi senza darci una risposta.” Scrivete un programma in Python che ricerchi la soluzione a questo quesito. Suggerimento: potrebbe esservi utile il metodo delle stringhe zfill. Soluzione: http://thinkpython2.com/code/cartalk3.py. |
ContributeIf you would like to make a contribution to support my books, you can use the button below. Thank you!
Are you using one of our books in a class?We'd like to know about it. Please consider filling out this short survey.
|