Python: cicli <strong>for</strong> e <strong>while</strong> per elaborare file di testo in modo efficien

by theArchitect
SHARE
Python: cicli <strong>for</strong> e <strong>while</strong> per elaborare file di testo in modo efficien
© Guida-HTML5.it

Introduzione

I cicli for e while sono tra gli strumenti più importanti in Python quando bisogna ripetere operazioni su grandi quantità di dati. Un caso molto pratico, spesso sottovalutato, è l’elaborazione di file di testo: log applicativi, esportazioni CSV, report, file di configurazione o semplici liste di righe.

In questi scenari non basta “leggere il file”: serve spesso scorrere le righe, filtrare contenuti, contare occorrenze, cercare pattern e fermarsi appena si trova l’informazione utile. Qui i cicli diventano fondamentali, perché permettono di lavorare in modo ordinato, leggibile e soprattutto efficiente.

In questo tutorial vedremo come usare for e while per analizzare un file di testo riga per riga, gestire una ricerca semplice e produrre un piccolo report finale. L’obiettivo è mostrare un uso realistico e professionale dei cicli, con attenzione alla chiarezza del codice.

Codice completo

from pathlib import Path

def crea_file_di_esempio(percorso: Path) -> None:
    """Crea un file di testo di esempio con righe miste."""
    contenuto = [
        "INFO 2026-01-10 Avvio del servizio",
        "WARNING 2026-01-10 Memoria quasi esaurita",
        "INFO 2026-01-10 Connessione stabilita",
        "ERROR 2026-01-10 Timeout durante la richiesta",
        "INFO 2026-01-10 Operazione completata",
        "ERROR 2026-01-10 Impossibile salvare il file",
        "INFO 2026-01-10 Chiusura del servizio",
    ]
    percorso.write_text("n".join(contenuto), encoding="utf-8")


def analizza_log(percorso: Path, parola_chiave: str) -> dict:
    """
    Analizza un file di testo riga per riga.
    Conta le righe totali, gli errori e le righe che contengono una parola chiave.
    """
    totale_righe = 0
    numero_errori = 0
    righe_trovate = []

    # Ciclo for: ideale per scorrere un file riga per riga
    with percorso.open("r", encoding="utf-8") as file:
        for numero_riga, riga in enumerate(file, start=1):
            totale_righe += 1
            riga = riga.strip()

            if "ERROR" in riga:
                numero_errori += 1

            if parola_chiave.lower() in riga.lower():
                righe_trovate.append((numero_riga, riga))

    return {
        "totale_righe": totale_righe,
        "numero_errori": numero_errori,
        "righe_trovate": righe_trovate,
    }


def cerca_prima_occorrenza(percorso: Path, testo_da_trovare: str) -> tuple[int, str] | None:
    """
    Cerca la prima riga che contiene il testo richiesto.
    Usa un ciclo while per mostrare un controllo manuale dell´iterazione.
    """
    righe = percorso.read_text(encoding="utf-8").splitlines()
    indice = 0

    # Ciclo while: utile quando vogliamo controllare esplicitamente l´indice
    while indice < len(righe):
        riga = righe[indice]

        if testo_da_trovare.lower() in riga.lower():
            return indice + 1, riga

        indice += 1

    return None


def stampa_report(risultati: dict) -> None:
    print("=== REPORT ANALISI FILE ===")
    print(f"Totale righe: {risultati[´totale_righe´]}")
    print(f"Righe con ERROR: {risultati[´numero_errori´]}")
    print("Righe che contengono la parola chiave:")

    for numero_riga, testo in risultati["righe_trovate"]:
        print(f"  - Riga {numero_riga}: {testo}")


def main() -> None:
    file_log = Path("esempio_log.txt")
    crea_file_di_esempio(file_log)

    risultati = analizza_log(file_log, parola_chiave="servizio")
    stampa_report(risultati)

    ricerca = cerca_prima_occorrenza(file_log, "Timeout")
    if ricerca is not None:
        numero_riga, testo = ricerca
        print("nPrima occorrenza trovata:")
        print(f"Riga {numero_riga}: {testo}")
    else:
        print("nNessuna occorrenza trovata.")


if __name__ == "__main__":
    main()

Spiegazione

Vediamo il programma pezzo per pezzo. Il file di esempio contiene righe di log con livelli diversi: INFO, WARNING ed ERROR. Questo tipo di struttura è molto comune nei sistemi reali, perché permette di registrare eventi e diagnosticare problemi.

1. Creazione del file di esempio

La funzione crea_file_di_esempio scrive un piccolo file di testo. È utile per testare il codice senza dover preparare manualmente un file esterno ogni volta. In un progetto reale questa funzione non servirebbe necessariamente, ma è perfetta per esercitarsi.

2. Lettura con for

La funzione analizza_log usa un ciclo for per leggere il file riga per riga:

  • enumerate(file, start=1) restituisce sia il numero di riga sia il contenuto.
  • strip() rimuove spazi e a capo inutili.
  • La condizione "ERROR" in riga incrementa il contatore degli errori.
  • La ricerca della parola chiave usa un confronto case-insensitive con lower().

Questo approccio è molto efficiente perché non carica tutto il file in una struttura complessa: il ciclo scorre le righe in modo naturale e leggibile.

3. Ricerca con while

La funzione cerca_prima_occorrenza mostra un uso diverso del ciclo while. Qui non stiamo iterando “automaticamente” su un oggetto iterabile, ma gestiamo noi l’indice indice.

Il ciclo continua finché indice < len(righe). Ad ogni iterazione controlla la riga corrente e, se trova il testo richiesto, restituisce subito il risultato con return. Questo è un caso d’uso utile quando serve un controllo più esplicito del flusso.

4. Produzione del report

La funzione stampa_report mostra come presentare i dati raccolti. Anche qui troviamo un ciclo for, ma questa volta serve a stampare l’elenco delle righe trovate. È un esempio semplice ma realistico di separazione delle responsabilità: una funzione analizza, un’altra stampa.

5. Funzione main

La funzione main coordina l’intero processo: crea il file, lo analizza, stampa il report e cerca una prima occorrenza specifica. Questa struttura rende il programma più ordinato e facile da estendere.

Best practice

Quando usi cicli for e while per elaborare file o dati testuali, alcune buone pratiche fanno davvero la differenza:

  • Usa for quando scorre un iterabile: file, liste, tuple e generatori sono casi ideali.
  • Usa while quando controlli manualmente una condizione: per esempio un indice, un tentativo di ricerca o una ripetizione legata a uno stato.
  • Apri i file con with: garantisce la chiusura automatica della risorsa, anche in caso di errore.
  • Evita di caricare file enormi in memoria se non serve: iterare direttamente sul file è spesso più efficiente.
  • Normalizza il testo con strip(), lower() o upper() quando fai confronti.
  • Separa logica e output: una funzione per analizzare, una per stampare, una per orchestrare.
  • Usa nomi chiari per variabili e funzioni: il codice diventa più facile da mantenere.

Un altro consiglio importante: se devi fermarti appena trovi un valore, while o for con return possono essere perfetti. Se invece devi esaminare tutto il contenuto, il for è spesso la scelta più naturale.

Riepilogo

In questo tutorial abbiamo visto un sotto-argomento molto pratico: l’uso di for e while per elaborare file di testo. Il ciclo for è ideale per scorrere le righe in modo semplice e leggibile, mentre il ciclo while è utile quando vuoi controllare direttamente l’avanzamento dell’iterazione.

Abbiamo anche costruito un esempio concreto che:

  • crea un file di log di esempio;
  • conta le righe e gli errori;
  • cerca righe contenenti una parola chiave;
  • trova la prima occorrenza di un testo specifico;
  • stampa un report finale in modo ordinato.

Questo tipo di approccio è molto comune in automazione, analisi dati e manutenzione di piccoli tool Python. Padroneggiare bene i cicli significa scrivere codice più robusto, più chiaro e più utile nella pratica.

Approfondisci con risorse ufficiali

  • Python Tutorial - Control Flow Tools: documentazione ufficiale sui cicli e sul controllo del flusso.
  • Python Tutorial - Reading and Writing Files: guida ufficiale alla gestione dei file.
  • Built-in Functions: approfondimento su enumerate(), len(), print() e altre funzioni integrate.
  • pathlib: modulo moderno e consigliato per lavorare con percorsi e file.

Consulta la documentazione ufficiale di Python per consolidare questi concetti e scoprire varianti più avanzate, come l’uso di generatori, espressioni condizionali e gestione degli errori durante la lettura dei file.

SHARE