Lezione 7 Python Le Stringhe

      Nessun commento su Lezione 7 Python Le Stringhe

Tipi di dati composti

Finora abbiamo visto tre tipi di dati: int, float e string. Le stringhe sono qualitativamente diverse dagli altri tipi di dati poich ́e sono composte di unità più piccole: i caratteri.

I tipi di dati che sono fatti di elementi più piccoli sono detti tipi di dati composti. A seconda di ciò che stiamo facendo possiamo avere la necessità di trattare un tipo composto come fosse una singola entità o possiamo voler agire sulle sue singole parti. Questa duplice possibilità è molto utile.

L’operatore porzione seleziona dei caratteri da una stringa:

[code lang=”objc”]
<pre>>>> Frutto = "banana"
>>> Lettera = Frutto[1]
>>> print Lettera
[/code]

L’espressione Frutto[1] seleziona il carattere numero 1 dalla stringa Frutto. La variabile Lettera contiene il risultato. Quando stampiamo Lettera abbiamo però una sorpresa:

a

La prima lettera di “banana” logicamente non è “a”: in informatica i conteggi partono spesso da 0 e non da 1 come potrebbe sembrare normale e per accedere al primo carattere di una stringa dobbiamo quindi richiedere il numero 0, per il secondo il numero 1 e così via. Sembra un pò illogico ma ci farete facilmente l’abitudine perché questo è il modo normale di contare in molti linguaggi di programmazione. Quindi se vogliamo sapere l’iniziale della stringa scriviamo:

>>> Lettera = Frutto[0]
>>> print Lettera
b

L’espressione tra parentesi quadrate è chiamata indice. Un indice identifica un particolare elemento di un insieme ordinato che nel nostro caso è l’insieme dei caratteri di una stringa. L’indice può essere una qualsiasi espressione intera.

Lunghezza

La funzione len ritorna il numero di caratteri di una stringa:

>>> Frutto = "banana"
>>> len(Frutto)
6

Per ottenere l’ultimo carattere di una stringa potresti essere tentato di fare qualcosa di simile a:

Lunghezza = len(Frutto)
Ultimo = Frutto[Lunghezza]       # ERRORE!

ma c’è qualcosa che non va: infatti ottieni un errore IndexError: string index out of rangedatochestaifacendoriferimentoall’indice6quandoquelli validi vanno da 0 a 5. Per ottenere l’ultimo carattere dovrai quindi scrivere:

Lunghezza = len(Frutto)
Ultimo = Frutto[Lunghezza-1]

In alternativa possiamo usare indici negativi che in casi come questo sono più comodi, contando a partire dalla fine della stringa: l’espressione Frutto[-1] ritorna l’ultimo carattere della stringa, Frutto[-2] il penultimo e così via.

Elaborazione trasversale e cicli for

Molti tipi di elaborazione comportano un’azione su una stringa un carattere per volta. Spesso queste elaborazioni iniziano dal primo carattere, selezionano un carattere per volta e continuano fino al completamento della stringa. Questo tipo di elaborazione è definita elaborazione trasversale o attraversamento, in quanto attraversa la stringa dall’inizio alla fine. Un modo per implementare un’elaborazione trasversale è quello di usare un ciclo while:

[code lang=”objc”]
Indice = 0
while Indice < len(Frutto):
Lettera = Frutto[Indice]
print Lettera
Indice = Indice + 1
[/code]

Questo ciclo attraversa la stringa e ne mostra una lettera alla volta, una per riga. La condizione del ciclo è Indice < len(Frutto) così che quando Indice è uguale alla lunghezza della stringa la condizione diventa falsa, il corpo del ciclo non è eseguito ed il ciclo termina. L’ultimo carattere cui si accede è quello con indice len(Frutto)-1 che è l’ultimo carattere della stringa.

Usare un indice per attraversare un insieme di valori è un’operazione così comune che Python fornisce una sintassi ancora più semplice: il ciclo for.

for Lettera in Frutto:
  print Lettera

Ad ogni ciclo, Lettera assume il valore del prossimo carattere della stringa Frutto, così che Frutto viene attraversata completamente finch ́e non rimangono più caratteri da analizzare.

Porzioni di stringa

Un segmento di stringa è chiamato porzione. La selezione di una porzione è simile alla selezione di un carattere:

[code lang=”objc”]
&gt;&gt;&gt; s = &quot;Pietro, Paolo e Maria&quot;
&gt;&gt;&gt; print s[0:6]
Pietro
&gt;&gt;&gt; print s[8:13]
Paolo
&gt;&gt;&gt; print s[16:21]
Maria
[/code]

L’operatore [n:m] ritorna la stringa a partire dall’ “n-esimo” carattere incluso fino all’ “m-esimo” escluso.

Se non `e specificato il primo indice (prima dei due punti 🙂 la porzione parte dall’inizio della stringa. Senza il secondo indice la porzione finisce con il termine della stringa:

[code lang=”objc”]
&gt;&gt;&gt; Frutto = &quot;banana&quot;
&gt;&gt;&gt; Frutto[:3]
’ban’
&gt;&gt;&gt; Frutto[3:]
‘ana’
[/code]

Confronto di stringhe

Gli operatori di confronto operano anche sulle stringhe. Per vedere se due stringhe sono uguali:

if Parola == "BANANA":
  print  "stai parlando di un frutto!"

Altri operatori di confronto sono utili per mettere le parole in ordine alfabetico:

if Parola < "BANANA":
  print "la tua parola" + Parola + "viene prima di BANANA."
elif Parola > "BANANA":
  print "la tua parola" + Parola + "viene dopo BANANA."
else:
  print "hai inserito la parola BANANA"

Devi comunque fare attenzione al fatto che Python non gestisce le parole maiuscole e minuscole come facciamo noi in modo intuitivo: in un confronto le lettere maiuscole vengono sempre prima delle minuscole, così che:

"BANANA" < "BAnana" < "Banana" < "bANANA" < "banana"
"ZEBRA" < "banana"

Un modo pratico per aggirare il problema è quello di convertire le stringhe ad un formato standard (tutto maiuscole o tutto minuscole) prima di effettuare il confronto.

Le stringhe sono immutabili

Si può essere tentati di usare l’operatore porzione [] alla sinistra di un’assegnazione, con l’intenzione di cambiare un carattere di una stringa:

Saluto = "Ciao!"
Saluto[0] = ’M’            # ERRORE!
print Saluto

Invece di ottenere Miao! questo codice stampa il messaggio d’errore TypeError: object doesn’t support item assignment.

Le stringhe sono infatti immutabili e ciò significa che non puoi cambiare una stringa esistente. L’unica cosa che puoi eventualmente fare è creare una nuova stringa come variante di quella originale:

Saluto = "Ciao!"
NuovoSaluto = ’M’ + Saluto[1:]
print NuovoSaluto

Abbiamo concatenato la nuova prima lettera ad una porzione di Saluto, e questa operazione non ha avuto alcun effetto sulla stringa originale.

Funzione Trova

Secondo te cosa fa questa funzione?

[code lang=”objc”][/code]
def Trova(Stringa, Carattere):
Indice = 0
while Indice < len(Stringa):
if Stringa[Indice] == Carattere:
return Indice
Indice = Indice + 1
return -1
[/code
In un certo senso questa funzione Trova è l’opposto dell’operatore porzione []: invece di prendere un indice e trovare il carattere corrispondente cerca in una stringa la posizione dove appare un carattere e ne restituisce l’indice. Se il carattere non è presente la funzione restituisce -1.

Questo è il primo esempio di return all’interno di un ciclo. Se Stringa[Indice] == Carattere il ciclo viene interrotto prematuramente. Se il carattere non fa parte della stringa il programma termina normalmente e ritorna -1.

Cicli e contatori

Questo programma conta il numero di volte in cui la lettera ’a’ compare in una stringa, usando un contatore:

Frutto = "banana"
Conteggio = 0
for Carattere in Frutto:
  if Carattere == ’a’:
    Conteggio = Conteggio + 1
print Conteggio

La variabile Conteggio è inizializzata a 0 e poi incrementata ogni volta che è trovata una ’a’ (incrementare significa aumentare di 1; è l’opposto di decrementare). Al termine del ciclo Conteggio contiene il risultato e cioè il numero totale di lettere a nella stringa.

page93image5120

Il modulo string

Il modulo string contiene funzioni molto utili per la manipolazione delle stringhe. Come abbiamo già visto prima di poter usare un modulo lo dobbiamo importare:

>>> import string

Il modulo string include una funzione chiamata find che fa le stesse cose della nostra funzione Trova. Per poterla usare, dopo avere importato il modulo, dobbiamo chiamarla usando la notazione punto (NomeDelModulo.NomeDellaFunzione):

>>> Frutto = "banana"
>>> Posizione = string.find(Frutto, "a")
>>> print Posizione
1

In realtà string.find è più generale della nostra Trova. In primo luogo possiamo usarla per cercare stringhe e non soltanto caratteri:

>>> string.find("banana", "na")
2

Inoltre ammette un argomento ulteriore per specificare da dove vogliamo iniziare la nostra ricerca:

>>> string.find("banana", "na", 3)
4

Ancora, può prendere due argomenti che specificano il dominio di ricerca, cioè la porzione di stringa originale dove vogliamo effettuare la ricerca:

>>> string.find("bob", "b", 1, 2)
-1

In questo esempio la ricerca fallisce perch ́e la lettera ’b’ non appare nel dominio definito dagli indici 1 e 2 (da 1 incluso fino a 2 escluso).

Classificazione dei caratteri

E` spesso necessario esaminare un carattere e controllare se questo è maiuscolo, minuscolo, o se si tratta di una cifra o di uno spazio bianco. A questo scopo il modulo string fornisce parecchie costanti molto utili.

La stringa string.lowercase contiene tutti i caratteri che il sistema considera minuscoli. Allo stesso modo string.uppercase contiene tutti i caratteri maiuscoli. Guarda cosa contengono queste stringhe:

>>> print string.lowercase
>>> print string.uppercase
>>> print string.digits

Possiamo usare queste costanti e la funzione find per classificare i caratteri. Per esempio se find(string.lowercase, Carattere) ritorna un valore diverso da -1 allora Carattere è minuscolo (un valore diverso da -1 indicherebbe infatti la posizione del carattere trovato):

def Minuscolo(Carattere):
  return string.find(string.lowercase, Carattere) != -1

In alternativa possiamo usare l’operatore in che determina se un carattere compare in una stringa:

def Minuscolo(Carattere):
  return Carattere in string.lowercase

o il consueto operatore di confronto:

def Minuscolo(Carattere):
  return ’a’ <= Carattere <= ’z’

Se Carattere è compreso tra ’a’ e ’z’ deve per forza trattarsi di una lettera minuscola.

Esercizio: prova a determinare quale di queste versioni è la più  veloce. Puoi pensare ad altre ragioni, a parte la velocità, per preferire una versione piuttosto che un’altra?

Un’altra costante definita nel modulo string può sorprendervi quando provate a stamparla:

>>> print string.whitespace

I caratteri spazi bianchi infatti muovono il cursore senza stampare nulla: sono questi che creano lo spazio bianco tra i caratteri visibili. La costante string.whitespace contiene tutti gli spazi bianchi inclusi lo spazio, la tabula- zione (\t) ed il ritorno a capo (\n).