Capitolo 3.5 · Stringhe¶
Cosa impari
- che cos'è una stringa e come si calcola la sua lunghezza con
len; - a unire e ripetere stringhe con
+e*, e a convertire numeri in stringhe e viceversa; - a leggere singoli caratteri e porzioni di stringa con gli indici e lo slicing;
- a usare
ord,chr, le sequenze di escape e i metodilower,upper,replace; - a formattare l'output con l'operatore
%e con le f-string.
Molti programmi elaborano testi, non soltanto numeri: nomi, codici, indirizzi, numeri di telefono. In questo capitolo impari a lavorare con le stringhe: prenderne un pezzo, unirle, trasformarle e mostrarle in modo ordinato.
Il tipo stringa¶
Una stringa è una sequenza di caratteri: lettere, cifre, spazi, simboli. Ogni carattere appartiene allo standard Unicode, che assegna un numero a ogni carattere esistente. La stringa è un tipo strutturato (o non scalare): è composta da unità più piccole, i caratteri.
Una stringa si scrive tra doppi apici ("hello") oppure tra apici singoli ('hello'). Le due forme sono equivalenti.
Il numero di caratteri di una stringa si chiama lunghezza e si calcola con la funzione len. Una stringa senza caratteri, scritta "" oppure '', si chiama stringa vuota e ha lunghezza 0.
ciao = "hello"
ciao2 = 'hello world'
print(len(ciao)) # 5
print(len(ciao2)) # 11: anche lo spazio è un carattere
vuota = ""
print(len(vuota)) # 0
Concatenazione e ripetizione¶
L'operatore + tra due stringhe le concatena: il risultato contiene tutti i caratteri della prima, seguiti da tutti quelli della seconda. Python non aggiunge spazi da solo: se ti serve uno spazio, devi concatenare la stringa " ".
nome = "Mario"
cognome = "Rossi"
persona = nome + cognome
print(persona) # MarioRossi
persona = nome + " " + cognome
print(persona) # Mario Rossi
L'operatore * tra una stringa e un numero intero ripete la stringa. Il numero può stare a sinistra o a destra del *. È comodo, ad esempio, per disegnare una linea di 50 trattini senza scriverli tutti a mano.
Lo stesso operatore, compiti diversi
+ e * fanno cose diverse a seconda dei valori: tra due numeri + somma, tra due stringhe concatena. Questo si chiama operator overloading (sovraccarico degli operatori). Però stringa + numero non è permesso: Python segnala un errore.
Conversioni tra numeri e stringhe¶
Non puoi concatenare una stringa con un numero. Prima devi convertire il numero in stringa con la funzione str. Questa conversione si chiama type casting.
nome = "Mario"
codice = 1729
# agente = nome + codice # TypeError: non si unisce una stringa con un int
valore = str(codice)
agente = nome + valore
print(agente) # Mario1729
Al contrario, se una stringa contiene un numero scritto correttamente, la puoi trasformare in un valore numerico con int o float. Ti serve soprattutto con input, che restituisce sempre una stringa.
val = int("1729")
price = float("17.29")
print(val + 1) # 1730: ora è un numero, si può sommare
print(price * 2) # 34.58
Se la stringa non rappresenta un numero valido, il programma si ferma con un ValueError. L'esempio che segue mostra apposta questo errore.
Accesso ai caratteri: gli indici¶
Ogni carattere di una stringa ha una posizione, detta indice. Il primo carattere ha indice 0, il secondo 1, e così via.
| Carattere | H |
a |
r |
r |
y |
|---|---|---|---|---|---|
| Indice | 0 | 1 | 2 | 3 | 4 |
Per leggere un carattere scrivi l'indice tra parentesi quadre: nome[0]. L'ultimo indice è sempre len(nome) - 1, perché si parte da 0.
nome = "Harry"
primo = nome[0]
ultimo = nome[4]
print(primo, ultimo) # H y
pos = len(nome) - 1 # 5 - 1 = 4
print(nome[pos]) # y
Se usi un indice fuori dalle posizioni valide, durante l'esecuzione ottieni un IndexError (index out of range, indice fuori dall'intervallo). L'esempio che segue mostra apposta questo errore: "Harry" ha 5 caratteri, quindi gli indici vanno da 0 a 4.
Indici negativi¶
Gli indici possono anche essere negativi: si conta da destra. L'ultimo carattere ha indice -1, il penultimo -2 e così via fino al primo.
| Carattere | H |
a |
r |
r |
y |
|---|---|---|---|---|---|
| Indice positivo | 0 | 1 | 2 | 3 | 4 |
| Indice negativo | -5 | -4 | -3 | -2 | -1 |
stringa = "Harry"
print(stringa[0], stringa[-5]) # H H: stesso carattere
print(stringa[-1]) # y: l'ultimo, senza usare len
Le stringhe sono immutabili¶
In Python le stringhe sono immutabili: dopo averle create non puoi cambiare i loro caratteri. Se ci provi ottieni un TypeError. L'esempio che segue mostra apposta questo errore.
nome = "Bob"
print(nome[0])
nome[0] = 'G' # TypeError: 'str' object does not support item assignment
Puoi però assegnare alla variabile una stringa nuova. La stringa vecchia non cambia: la variabile ora fa riferimento a un'altra stringa.
Slicing: prendere una porzione di stringa¶
Lo slicing estrae una parte di una stringa, detta slice (fetta). La sintassi è stringa[start:end]:
startè l'indice del primo carattere, incluso;endè l'indice dove fermarsi, escluso.
Nella stringa "Corso di Elementi di Informatica" la parola Elementi va dall'indice 9 (la E) all'indice 16 (la i). Quindi si scrive [9:17]: il 17 è escluso.
stringa = "Corso di Elementi di Informatica"
print(stringa[9:17]) # 'Elementi'
print(stringa[9:16]) # 'Element': manca l'ultima lettera
print(stringa[9:18]) # 'Elementi ': c'è anche lo spazio
Entrambi gli indici sono facoltativi:
- se ometti
start, si parte dal primo carattere (indice 0); - se ometti
end, si arriva fino all'ultimo carattere; stringa[:]è una copia dell'intera stringa.
stringa = "Elementi di Informatica"
print(stringa[:8]) # 'Elementi'
print(stringa[9:]) # 'di Informatica'
print(stringa[:]) # 'Elementi di Informatica'
print(stringa[-3:]) # 'ica': gli ultimi tre caratteri
Slicing con passo¶
Puoi aggiungere un terzo numero, il passo (step): stringa[start:end:step]. Se non lo scrivi, il passo vale 1 e si prendono tutti i caratteri. Con passo 2 si prende un carattere sì e uno no.
Il passo può essere anche negativo: allora ci si sposta all'indietro e i caratteri escono in ordine inverso. In questo caso start deve essere maggiore di end. Con [::-1] ottieni l'intera stringa al contrario.
stringa = "Elementi di Informatica"
print(stringa[22:5:-1]) # 'acitamrofnI id it'
print(stringa[::-1]) # tutta la stringa al contrario
Come ricordare dove finisce lo slice
In stringa[start:end] il numero di caratteri estratti è end - start. Ad esempio stringa[9:17] restituisce 17 − 9 = 8 caratteri, proprio come le 8 lettere di Elementi.
I codici dei caratteri: ord e chr¶
Il computer memorizza ogni carattere come un numero: il suo codice Unicode, scritto in binario. Python ha due funzioni per passare dal carattere al numero e viceversa:
ord(carattere)restituisce il codice Unicode del carattere;chr(codice)restituisce il carattere che ha quel codice.
Le lettere maiuscole e minuscole hanno codici diversi: tra A (65) e a (97) la distanza è 32.
print('a:', ord('a'), 'A:', ord('A'))
print('Distanza tra maiuscola e minuscola:', ord('a') - ord('A'))
print('Lettera corrispondente a code 68: ', chr(68))
print('Lettera corrispondente a code 75: ', chr(75))
print(chr(ord('a') - 32)) # A
print(chr(ord('A') + 32)) # a
Sequenze di escape¶
Come scrivi una stringa che contiene le virgolette? Metti un backslash (\) prima delle virgolette. Il backslash non compare nella stringa: dice solo a Python che le virgolette che seguono fanno parte del testo. Un backslash seguito da un carattere si chiama sequenza di escape.
| Sequenza | Significato |
|---|---|
\" |
virgolette doppie dentro la stringa |
\' |
apice singolo dentro la stringa |
\n |
a capo (newline): inizia una nuova riga |
\t |
tabulazione orizzontale |
\\ |
il carattere backslash |
print("Lui disse: \"Ciao!\"")
print('L\'esame è domani')
print("Prima riga\nSeconda riga")
print("Nome\tVoto")
print("Anna\t28")
Funzioni e metodi¶
In Python ogni valore è un oggetto. Un metodo è una funzione che appartiene a un certo tipo di oggetto: ad esempio, tutte le stringhe hanno gli stessi metodi. Un metodo si chiama con la notazione del punto: oggetto.metodo().
| Funzioni | Metodi |
|---|---|
| sono generali, accettano argomenti di tipi diversi | sono specifici di un tipo (stringhe, interi, ...) |
si chiamano così: len(s) |
si chiamano con il punto: s.upper() |
il risultato si salva in una variabile: n = len(s) |
il risultato si salva in una variabile: m = s.upper() |
Tre metodi delle stringhe molto utili:
| Metodo | Restituisce |
|---|---|
s.lower() |
la versione di s tutta in minuscolo |
s.upper() |
la versione di s tutta in maiuscolo |
s.replace(old, new) |
una nuova stringa in cui ogni old è sostituito da new |
Ricorda che le stringhe sono immutabili: i metodi non cambiano s, ma restituiscono una stringa nuova. Se vuoi conservarla, devi assegnarla a una variabile.
s = "Elementi di Informatica"
print(s.lower())
print(s.upper())
print(s.replace("i", "1"))
s.upper()
print(s) # s non è cambiata!
s = s.upper()
print(s) # ora sì: abbiamo assegnato il risultato
I metodi lower e upper sono comodi nei confronti. Nel capitolo 3 hai visto che 'Prospero' è diverso da 'prospero'. Se converti la risposta in minuscolo, l'utente può scrivere come vuole.
risposta = input('Vuoi continuare? (si/no) ')
if risposta.lower() == 'si':
print('Continuiamo!')
else:
print('Ci fermiamo qui.')
Prova a rispondere si, SI e Si: il programma continua in tutti e tre i casi.
Leggere dati con input¶
La funzione input mostra un messaggio (il prompt) e aspetta che l'utente scriva qualcosa e prema Invio. Restituisce sempre una stringa. Per leggere un numero, prima leggi la stringa e poi la converti con int o float.
nome = input("Inserisci il tuo nome: ")
eta_stringa = input("Inserisci la tua età: ")
eta = int(eta_stringa)
print(nome, "tra un anno avrai", eta + 1, "anni")
Qui eta_stringa è una variabile temporanea: serve solo a contenere il testo prima della conversione. Di solito si scrive tutto in una riga: eta = int(input("Inserisci la tua età: ")).
Output formattato¶
Spesso vuoi inserire dei numeri in un testo e mostrarli in modo ordinato, ad esempio sempre con due decimali. Python offre diverse soluzioni: la concatenazione, l'operatore %, le f-string e il metodo .format(). Qui vediamo l'operatore % e le f-string.
L'operatore di formattazione %¶
Tra due numeri interi % calcola il resto della divisione. Se invece a sinistra c'è una stringa, % diventa l'operatore di formato. Nella stringa scrivi degli specificatori di formato (come %d): ognuno viene sostituito, nell'ordine, dai valori scritti dopo il %.
| Specificatore | Significato |
|---|---|
%s |
stringa (o altro valore mostrato come testo, ad esempio un numero) |
%d |
numero intero |
%f |
numero reale (float), di default con 6 decimali |
%.2f |
numero reale con 2 cifre dopo il punto |
%10.2f |
numero reale con 2 decimali in un campo largo 10 caratteri, allineato a destra |
%-10s |
stringa in un campo largo 10, allineata a sinistra (il -) |
%x |
numero intero in base 16 (esadecimale) |
prezzo = 0.7523
print("Prezzo al litro intero: %d" % (prezzo))
print("Prezzo al litro reale: %f" % (prezzo))
print("Prezzo al litro reale con due cifre decimali: %.2f" % (prezzo))
print("Prezzo al litro reale con due cifre decimali su 10 spazi: %10.2f" % (prezzo))
valore = 10
print("Valore hex: %x" % (valore))
titolo = "Quantità"
print("%10s:%10d" % (titolo, 24))
print("%-10s:%10d" % (titolo, 24))
Nota che %d con 0.7523 mostra 0: la parte decimale viene troncata.
Le f-string¶
Una f-string è una stringa preceduta dalla lettera f (o F). Dentro puoi scrivere, tra parentesi graffe {}, una variabile o un'espressione: Python la calcola al momento dell'esecuzione e mette il risultato al suo posto. Se aggiungi = dopo il nome, viene mostrato anche il nome della variabile: è utile per controllare i valori mentre scrivi il programma.
result = 5
a = 7
b = 8
print(f"the result is {result}")
print(f"the sum is {a+b}")
print(f"the result is {result=}")
Per decidere come mostrare un valore, scrivi uno specificatore di formato dopo i due punti: {valore:specifica}.
| Specificatore | Significato |
|---|---|
<, >, ^ |
allinea a sinistra, a destra o al centro nello spazio disponibile |
s |
formato stringa (è quello di default, si può omettere) |
+ |
mostra sempre il segno, anche per i numeri positivi |
b, d, o, x |
intero in binario, decimale, ottale, esadecimale |
f, e |
numero reale in notazione fissa o esponenziale |
Per i numeri reali il formato più usato è {valore:ampiezza.precisionef}:
- ampiezza: numero minimo di caratteri stampati (cifre, segno e punto compresi). Lo spazio in più è riempito con spazi e il numero è allineato a destra;
- precisione: numero di cifre dopo il punto decimale.
Nell'esempio, import math permette di usare il valore di π già pronto in Python, math.pi.
valore = 20
print(f'Binario: {valore:b}')
print(f'Esadecimale: {valore:x}')
print(f'Ottale: {valore:o}')
import math
pi_greco = math.pi
print(f'{pi_greco:10.3f}')
print(f'{pi_greco:8.6f}')
nome = 'Anna'
print(f'[{nome:<10}]')
print(f'[{nome:>10}]')
print(f'[{nome:^10}]')
% o f-string?¶
Operatore % |
f-string |
|---|---|
"la tua età è %d" % (eta) |
f'la tua età è {eta}' |
nella stringa scrivi un segnaposto con il tipo (%d, %s, ...) |
la stringa è preceduta dalla lettera f |
i valori si scrivono dopo, in ordine: % (val1, val2) |
tra {} scrivi direttamente la variabile o un'espressione |
Le f-string sono più facili da leggere, perché vedi subito quale variabile va in quale punto.
Esempio completo: il distributore automatico¶
Un cliente sceglie un articolo e inserisce una banconota. Il distributore dà il resto con monete da un dollaro e da un quarto di dollaro (25 centesimi). I prezzi sono multipli di 25 centesimi. Quante monete di ogni tipo deve dare?
- Input: il prezzo dell'articolo (in centesimi) e il valore della banconota (in dollari).
- Output: il numero di monete da un dollaro e da un quarto.
Risoluzione a mano. L'articolo costa 2.25 $ e il cliente inserisce 5 $. Conviene ragionare in centesimi: il resto è 500 − 225 = 275 centesimi.
- 275 // 100 = 2 → 2 monete da un dollaro;
- 275 % 100 = 75 centesimi avanzano;
- 75 // 25 = 3 → 3 monete da un quarto.
CENTESIMI_PER_DOLLARO = 100
CENTESIMI_PER_QUARTO = 25
prezzo_articolo = int(input("Inserire prezzo articolo in centesimi: "))
banconota = int(input("Inserire banconota (solo valore numerico): "))
resto_dovuto = CENTESIMI_PER_DOLLARO * banconota - prezzo_articolo
resto_dollari = resto_dovuto // CENTESIMI_PER_DOLLARO
pf_resto_dollari = resto_dovuto % CENTESIMI_PER_DOLLARO
resto_quarti = pf_resto_dollari // CENTESIMI_PER_QUARTO
print(f'Monete da un dollaro: {resto_dollari:d} \nMonete da un quarto: {resto_quarti:d}')
Prova con 225 e 5 (2 dollari e 3 quarti), poi con 175 e 10 (8 dollari e 1 quarto). Nota il \n dentro la f-string: manda a capo il secondo messaggio.
Errori tipici¶
| Errore | Cosa succede | Come si corregge |
|---|---|---|
'Hai ' + 20 + ' anni' |
TypeError: non si concatena una stringa con un numero |
converti con str(20) oppure usa una f-string |
int('12,5') o int('ciao') |
ValueError: la stringa non è un numero intero valido |
controlla il testo; per i decimali usa float('12.5') |
nome[5] con nome = "Harry" |
IndexError: gli indici vanno da 0 a 4 |
l'ultimo indice è len(nome) - 1 oppure -1 |
nome[0] = 'G' |
TypeError: le stringhe sono immutabili |
crea una stringa nuova: nome = 'G' + nome[1:] |
s.upper() senza assegnare |
nessun errore, ma s resta uguale |
s = s.upper() |
s[9:16] per prendere 8 caratteri |
nessun errore, ma manca l'ultimo carattere | end è escluso: scrivi s[9:17] |
print('Totale: {totale}') |
stampa proprio {totale}, non il valore |
manca la f: f'Totale: {totale}' |
Esercizi¶
Esercizio 1 · Inizio e fine. Memorizza una stringa in una variabile. Mostra i primi tre caratteri, poi tre punti, poi gli ultimi tre caratteri. Con "Mississippi" il programma deve mostrare Mis...ppi. Prova poi con una parola di 4 lettere e con una di 2: che cosa succede?
Soluzione
Con "casa" ottieni cas...asa: le due parti si sovrappongono, perché la parola ha meno di 6 caratteri. Con "no" ottieni no...no: lo slicing non dà errore se gli indici escono dalla stringa, prende solo i caratteri che ci sono.
Esercizio 2 · Numero di telefono. Chiedi un numero di telefono di dieci cifre, come 4155551212. Mostralo nello stile statunitense: (415) 555-1212.
Soluzione
numero = input("Numero di telefono (10 cifre): ")
prefisso = numero[:3]
centrale = numero[3:6]
finale = numero[6:]
print("(" + prefisso + ") " + centrale + "-" + finale)
Con una f-string l'ultima riga diventa print(f"({prefisso}) {centrale}-{finale}").
Esercizio 3 · Palindromo. Una frase è palindroma se letta al contrario resta uguale, senza contare spazi e maiuscole: ad esempio I topi non avevano nipoti. Chiedi una frase e scrivi se è palindroma oppure no. Suggerimento: usa lower, replace e lo slicing con passo -1.
Soluzione
frase = input("Scrivi una frase: ")
pulita = frase.lower()
pulita = pulita.replace(" ", "")
if pulita == pulita[::-1]:
print(f'"{frase}" è palindroma')
else:
print(f'"{frase}" non è palindroma')
Prova con I topi non avevano nipoti (palindroma) e con Elementi di Informatica (non palindroma).