#!/usr/bin/env python3 """ Verifica duplicati di Email e Numeri di Telefono in un file Excel dei soci. """ import sys import re import argparse from collections import defaultdict import pandas as pd SEPARATORI_TELEFONO = re.compile(r"[;,/|\n]+") def normalizza_email(email: str) -> str: return str(email).strip().lower() def normalizza_telefono(n: str) -> str: """Rimuove spazi interni dal numero (es. '344 503 2906' -> '3445032906').""" return re.sub(r"\s+", "", n.strip()) def estrai_telefoni(cella: str) -> list[str]: if not cella or str(cella).strip() in ("", "nan"): return [] parti = SEPARATORI_TELEFONO.split(str(cella).strip()) return [normalizza_telefono(p) for p in parti if p.strip()] def analizza_duplicati(filepath: str, esempi: int = 5): print(f"\nCaricamento file: {filepath}") df = pd.read_excel(filepath, dtype=str) totale_righe = len(df) print(f"Righe totali: {totale_righe}") col_email = "Email" col_tel = "Numeri di telefono" if col_email not in df.columns: print(f"[ERRORE] Colonna '{col_email}' non trovata. Colonne disponibili: {df.columns.tolist()}") sys.exit(1) if col_tel not in df.columns: print(f"[ERRORE] Colonna '{col_tel}' non trovata. Colonne disponibili: {df.columns.tolist()}") sys.exit(1) # --- EMAIL --- email_occorrenze: dict[str, list[int]] = defaultdict(list) email_vuote = 0 for idx, val in df[col_email].items(): if pd.isna(val) or str(val).strip() == "": email_vuote += 1 continue norm = normalizza_email(val) email_occorrenze[norm].append(idx + 2) # +2: header riga 1, indice 0-based email_duplicate = {e: righe for e, righe in email_occorrenze.items() if len(righe) > 1} email_uniche = len(email_occorrenze) totale_email_duplicate = sum(len(r) - 1 for r in email_duplicate.values()) # --- TELEFONI --- tel_occorrenze: dict[str, list[int]] = defaultdict(list) tel_vuote = 0 totale_numeri_estratti = 0 for idx, val in df[col_tel].items(): if pd.isna(val) or str(val).strip() == "": tel_vuote += 1 continue numeri = estrai_telefoni(val) totale_numeri_estratti += len(numeri) for n in numeri: tel_occorrenze[n].append(idx + 2) tel_duplicate = {t: righe for t, righe in tel_occorrenze.items() if len(righe) > 1} tel_uniche = len(tel_occorrenze) totale_tel_duplicate = sum(len(r) - 1 for r in tel_duplicate.values()) # --- STAMPA REPORT --- sep = "=" * 60 print(f"\n{sep}") print(" REPORT DUPLICATI - EMAIL") print(sep) print(f" Righe totali : {totale_righe}") print(f" Righe senza email : {email_vuote}") print(f" Email univoche : {email_uniche}") print(f" Email con duplicati : {len(email_duplicate)}") print(f" Occorrenze duplicate extra : {totale_email_duplicate}") top_email = sorted(email_duplicate.items(), key=lambda x: len(x[1]), reverse=True) if email_duplicate else [] if top_email: n = min(esempi, len(top_email)) print(f"\n Top {n} email piu' duplicate:") print(f" {'#':<4} {'Email':<40} {'Volte':>6} Righe Excel (prime 6)") print(" " + "-" * 72) for i, (email, righe) in enumerate(top_email[:n], 1): righe_str = str(righe[:6])[1:-1] + ("..." if len(righe) > 6 else "") print(f" {i:<4} {email:<40} {len(righe):>6} {righe_str}") else: print("\n Nessun duplicato trovato.") print(f"\n{sep}") print(" REPORT DUPLICATI - NUMERI DI TELEFONO") print(sep) print(f" Righe totali : {totale_righe}") print(f" Righe senza telefono : {tel_vuote}") print(f" Numeri totali estratti : {totale_numeri_estratti}") print(f" Numeri univoci : {tel_uniche}") print(f" Numeri con duplicati : {len(tel_duplicate)}") print(f" Occorrenze duplicate extra : {totale_tel_duplicate}") top_tel = sorted(tel_duplicate.items(), key=lambda x: len(x[1]), reverse=True) if tel_duplicate else [] if top_tel: n = min(esempi, len(top_tel)) print(f"\n Top {n} numeri piu' duplicati:") print(f" {'#':<4} {'Numero':<20} {'Volte':>6} Righe Excel (prime 6)") print(" " + "-" * 60) for i, (tel, righe) in enumerate(top_tel[:n], 1): righe_str = str(righe[:6])[1:-1] + ("..." if len(righe) > 6 else "") print(f" {i:<4} {tel:<20} {len(righe):>6} {righe_str}") else: print("\n Nessun duplicato trovato.") print(f"\n{sep}") print(" RIEPILOGO GENERALE") print(sep) pct_email = len(email_duplicate) / email_uniche * 100 if email_uniche else 0 pct_tel = len(tel_duplicate) / tel_uniche * 100 if tel_uniche else 0 print(f" Email duplicate : {len(email_duplicate):>5} ({pct_email:.1f}% delle email univoche)") print(f" Telefoni duplicati : {len(tel_duplicate):>5} ({pct_tel:.1f}% dei numeri univoci)") print(sep) def main(): parser = argparse.ArgumentParser(description="Verifica duplicati email e telefoni in un file Excel.") parser.add_argument("file", help="Percorso del file Excel da analizzare") parser.add_argument("--esempi", type=int, default=5, help="Numero di esempi da mostrare per categoria (default: 5)") args = parser.parse_args() analizza_duplicati(args.file, args.esempi) if __name__ == "__main__": main()