Vai al contenuto principale

Ricerca e sostituzione di stringhe in Python: in, .find(), .index(), .count() e .replace()

Schemi pratici per trovare, contare e sostituire sottostringhe nel Python moderno.
· 8 min leggi

Scopri con l'IA

È normale ricorrere a .find() o .index() per verificare se un testo esiste in una stringa, per poi imbattersi in comportamenti strani come un ValueError o una corrispondenza mancata all’inizio della stringa. La distinzione tra maiuscole e minuscole, i limiti di slice sfasati di uno e il fatto che non esista un metodo .contains() su str aumentano la confusione. La soluzione è semplice: usa lo strumento giusto per il compito. Per i controlli di esistenza ci affidiamo all’operatore in, a .find()/.index() per le posizioni, a .count() per i conteggi e a .replace() per le sostituzioni, oltre a qualche tecnica sicura per Unicode quando serve l’insensibilità alle maiuscole/minuscole.

Come Python gestisce la ricerca di sottostringhe

Le stringhe di testo in Python sono Unicode. Le operazioni sulle sottostringhe distinguono tra maiuscole e minuscole per impostazione predefinita e sono implementate in C per velocità. Il modo più diretto per verificare se un testo compare all’interno di una stringa è l’operatore in, che restituisce un booleano usando l’implementazione __contains__() della stringa. Quando ti servono posizioni o conteggi, usa i metodi dedicati di str. I parametri opzionali start ed end seguono la semantica degli slice: start è inclusivo; end è esclusivo.

Contenimento con in

Usa "needle" in haystack quando ti interessa solo se la sottostringa esiste. È leggibile e ti evita di gestire indici.

text = "Banana bread"
print("ban" in text)   # False (case-sensitive)
print("Ban" in text)   # True

Per controlli case-insensitive, normalizza entrambi i lati. .casefold() è più attento a Unicode di .lower() ed è la mia scelta predefinita per i confronti senza distinzione tra maiuscole e minuscole.

pattern = "ban"
print(pattern.casefold() in text.casefold())  # True
  • Quando usarlo: controlli rapidi di esistenza, validazione dell’input, filtraggio di liste.
  • Caso limite: "" in s è sempre True (la stringa vuota è in ogni stringa).

Metodo str.find()

Sintassi

str.find() restituisce l’indice più basso della sottostringa, oppure -1 se non è trovata. I parametri opzionali start ed end limitano la ricerca.

s.find(substring, start=0, end=len(s))

Esempi e casi d’uso

Usa .find() quando ti serve la posizione e puoi gestire un valore “non trovato” senza eccezioni.

tagline = "Ship fast. Fix faster."
print(tagline.find("fast"))         # 5
print(tagline.find("fast", 6))      # 16
print(tagline.find("slow"))         # -1

Non scrivere if s.find(sub): per controllare l’esistenza. Se la corrispondenza è all’indice 0, la condizione è falsy.

name = "Alice"
if name.find("A"):         # Wrong: 0 is Falsey
    print("Found A")       # Will not run
if name.find("A") != -1:   # Correct
    print("Found A")

Metodo str.index()

Sintassi

.index() rispecchia .find() ma genera ValueError quando la sottostringa è assente.

s.index(substring, start=0, end=len(s))

Esempi e quando sceglierlo

Usa .index() quando la sottostringa deve esistere e un’eccezione è la modalità di errore corretta.

product = "USB-C Cable"
print(product.index("Cable"))  # 6

try:
    product.index("HDMI")
except ValueError:
    print("Required label missing")

Metodo str.count()

Sintassi

.count() restituisce il numero di occorrenze non sovrapposte. Accetta anche i limiti start ed end.

s.count(substring, start=0, end=len(s))

Esempi e casi limite

Usa .count() per conteggi rapidi senza regex.

log_line = "ERROR: timeout. ERROR: retry. ERROR: gave up."
print(log_line.count("ERROR"))     # 3
print(log_line.count("WARN"))      # 0

Caso speciale: la stringa vuota.

print("abc".count(""))   # 4 (len(s) + 1)

Metodo str.replace()

.replace() restituisce una nuova stringa in cui le occorrenze di old sono sostituite da new. Usa count per limitare le sostituzioni.

s.replace(old, new, count=-1)

Sostituire sottostringhe

Il metodo non è in-place; restituisce una copia.

message = "The red house is between the blue house and the old house"
print(message.replace("house", "car"))
# The red car is between the blue car and the old car

print(message.replace("house", "car", 2))
# The red car is between the blue car and the old house

Sostituzione case-insensitive

Per sostituzioni senza distinzione tra maiuscole e minuscole preservando i pattern di maiuscole, usa re.sub() con re.IGNORECASE, oppure normalizza con .casefold() se non ti serve preservare il casing originale.

Confronti case-insensitive con .casefold()

.casefold() offre una normalizzazione aggressiva e attenta a Unicode ed è preferibile a .lower() per confronti senza distinzione tra maiuscole e minuscole.

query = "straße"           # German 'straße'
text  = "STRASSE und mehr" # Uppercase variant
print(query.casefold() in text.casefold())  # True

Strumenti correlati per prefissi e suffissi

Per inizi/fini noti, usa i metodi dedicati: sono più veloci e chiari rispetto a slicing o regex:

  • s.startswith(prefix) e s.endswith(suffix) (accettano tuple per più opzioni)
  • s.removeprefix(prefix) e s.removesuffix(suffix) (Python 3.9+)
filename = "draft_report_v2.pdf"
print(filename.removeprefix("draft_"))  # report_v2.pdf
print(filename.endswith((".pdf", ".docx")))  # True

Lavorare con le colonne di Pandas

Quando cerchi in molte stringhe in una colonna di DataFrame, usa i metodi stringa vettorializzati. Imposta regex=False per cercare testo letterale.

import pandas as pd

cities = pd.Series(["New York", "Yorktown", None, "Toronto"], dtype="string")
mask = cities.str.contains("York", regex=False, na=False)
print(mask.tolist())  # [True, True, False, False]

Note:

  • Per impostazione predefinita, regex=True, quindi caratteri speciali come . corrispondono a qualsiasi carattere a meno che tu non disabiliti le regex.
  • Gestisci i null tramite na=.... Con StringDtype, i valori mancanti predefiniti sono False nella mask.

Errori comuni e casi limite

  • Nessun .contains() su str: usa "sub" in s. "abc".contains("a") genera AttributeError.

  • Veridicità di .find(): l’indice 0 è falsy; confronta con != -1 o preferisci in per l’esistenza.

  • .index() solleva eccezioni: gestisci ValueError se la sottostringa potrebbe essere assente.

  • Stringa vuota: "" in s è True; s.find("") restituisce 0; s.count("") è len(s)+1.

  • Distinzione tra maiuscole e minuscole: tutte le operazioni sono case-sensitive a meno che tu non normalizzi o usi flag regex.

  • Byte vs. testo: non mescolare bytes e str nelle ricerche; decodifica o codifica per far corrispondere i tipi.

  • Semantica delle sottostringhe: "ab" in "cat,bat" è False anche se "a" e "b" compaiono separatamente: le corrispondenze devono essere contigue.

Esempi pratici da eseguire

Questi brevi snippet mostrano i pattern corretti e mettono in evidenza i tranelli più comuni.

Controlli di esistenza

headline = "Where's Waldo?"
print("Waldo" in headline)          # True
print("Wenda" in headline)          # False
print(headline.find("Waldo"))       # 8
print(headline.find("Wenda"))       # -1

Ricerca limitata con start ed end

End è esclusivo, quindi le posizioni di ricerca rispecchiano la semantica degli slice.

headline = "Where's Waldo?"
print(headline.find("Waldo", 0, 6))   # -1 (searching "Where'")
print(headline.find("Waldo", 0, 13))  # 8  (searching up to the 'o' in Waldo)

Conteggio e sostituzione

inventory = "apple, apple, pear, apple"
print(inventory.count("apple"))                # 3
print(inventory.replace("apple", "orange", 2)) # orange, orange, pear, apple

Esercizio di pratica: ricerca e sostituzione di stringhe in Python 

Questo esempio elabora una lista di descrizioni di film. Mostra controlli di esistenza, ricerche limitate e sostituzioni sicure senza regex.

blurbs = [
    "Critics say the lead actor delivers a career-best performance.",
    "Fans argue the actor actor scene was intentionally repetitive.",
    "A clever cameo steals the show."
]

for blurb in blurbs:
    # Check whether "actor" appears between indexes 20 and 40 (end exclusive).
    window_has_actor = "actor".casefold() in blurb[20:40].casefold()
    if not window_has_actor:
        print("Window check: actor not found")
        continue

    # If "actor actor" appears, collapse to a single "actor".
    if "actor actor" in blurb:
        print(blurb.replace("actor actor", "actor"))
    # If "actor actor actor" appears, collapse to a single "actor".
    elif "actor actor actor" in blurb:
        print(blurb.replace("actor actor actor", "actor"))
    else:
        print(blurb)

Output:

Window check: actor not found
Fans argue the actor scene was intentionally repetitive.
Window check: actor not found

Conclusione

Usa l’operatore in per il semplice contenimento, .find() o .index() quando ti servono posizioni, .count() per conteggi non sovrapposti e .replace() per le sostituzioni. Normalizza con .casefold() per controlli case-insensitive e preferisci gli helper dedicati per prefissi/suffissi quando opportuno. Evitiamo di convertire i risultati di .find() in booleani e trattiamo il comportamento con sottostringa vuota come caso speciale per mantenere il codice sulle stringhe corretto e chiaro.

Argomenti

Correlato