AiAnonymize_2 / config /regex_patterns.py
Alessandro Tomassini
vs 2.0
fa1e652
"""Pattern regex per il rilevamento L0 (appalti italiani) + pattern di post-boost.
_REGEX_L0_RECOGNIZER — 20 PatternRecognizer Presidio per entità procurement.
POST_BOOST_PATTERNS — regex di validazione fullmatch (score +0.30 se match).
"""
import re as _re
from presidio_analyzer import Pattern, PatternRecognizer
def _r(entity: str, name: str, regex: str, score: float, context: list) -> PatternRecognizer:
return PatternRecognizer(
supported_entity=entity,
supported_language="it",
patterns=[Pattern(name, regex, score)],
context=context,
)
# ---------------------------------------------------------------------------
# L0 — PatternRecognizer per gare d'appalto italiane
# Il context in PatternRecognizer serve a boostare lo score
# quando certe parole chiave sono trovate vicine allo span rilevato dalla regex.
# ---------------------------------------------------------------------------
_REGEX_L0_RECOGNIZER: list[PatternRecognizer] = [
# CIG – Ordinario (\d{7}[0-9A-F]{3}) · Unico/Smart ([A-Z][0-9A-F]{9})
_r("CIG", "cig",
r"\b(?:\d{7}[0-9A-F]{3}|[A-Z][0-9A-F]{9})\b", 0.70,
["CIG", "cig", "Cig", "CIG:", "cig:", "CIG :", "cig :",
"codice CIG", "codice cig", "Codice CIG",
"codice identificativo gara", "Codice Identificativo Gara",
"codice identificativo della gara", "identificativo di gara",
"id gara", "ID gara", "ID Gara",
"smartcig", "SmartCIG", "smart CIG", "Smart CIG",
"lotto CIG", "lotto cig"]),
# CUP – struttura CIPE ufficiale (15 char)
_r("CUP", "cup",
r"\b[A-Z]\d{2}[A-Z][A-Z0-9]{2}\d{6}[A-Z0-9]{3}\b", 0.90,
["CUP", "cup", "Cup", "CUP:", "cup:", "CUP :", "cup :",
"codice CUP", "Codice CUP",
"codice unico di progetto", "Codice Unico di Progetto",
"codice unico progetto", "codice progetto",
"monitoraggio investimenti pubblici",
"investimento pubblico", "progetto pubblico"]),
# REA – sigla provincia + separatore + 4-7 cifre
_r("REA", "rea",
r"\b[A-Z]{2}[\s\-/\.]\d{4,7}\b", 0.85,
["REA", "rea", "Rea", "REA:", "rea:", "REA :", "REA n.",
"n. REA", "n. rea", "n.REA",
"registro imprese", "Registro Imprese", "registro delle imprese",
"registro economico amministrativo",
"CCIAA", "cciaa", "camera di commercio", "Camera di Commercio"]),
# Numero Gara ANAC – score basso (richiede context boost)
_r("NUMERO_GARA_ANAC", "num_gara",
r"\b\d{7,8}\b", 0.60,
["ANAC", "ANAC:", "ANAC :", "anac", "numero gara", "Numero Gara",
"n. gara", "N. gara", "N.Gara",
"identificativo gara", "Identificativo Gara", "identificativo gara:",
"id. gara", "ID gara", "numero identificativo gara",
"gara ANAC", "gara n.", "gara n°",
"SIMOG", "simog", "identificativo ANAC", "codice ANAC"]),
# PEC – domini certificati italiani
_r("PEC", "pec",
r"\b[\w.\-]+@[\w.\-]*(?:pec|postacert|legalmail|pecmail|"
r"sicurezzapostale|registerpec|ticertifica)[\w.\-]*\.\w+\b", 0.90,
["PEC", "pec", "Pec", "PEC:", "pec:", "indirizzo PEC",
"posta certificata", "Posta Certificata",
"posta elettronica certificata", "p.e.c.", "P.E.C."]),
# Matricola INPS – score basso (richiede context boost)
_r("MATRICOLA_INPS", "inps",
r"(?<!\d)\d{10}(?!\d)", 0.60,
["INPS", "inps", "matricola INPS", "matricola inps", "Matricola INPS",
"matricola:", "matricola n.", "n. matricola",
"previdenziale", "iscrizione INPS",
"posizione INPS", "posizione previdenziale"]),
# Polizza – formato lungo (GEN-2024-IT-NNNNNN)
_r("POLIZZA_ASSICURATIVA", "polizza_full",
r"\b[A-Z]{2,5}-\d{4}-[A-Z]{2}-\d{6,12}\b", 0.90,
["polizza", "Polizza", "polizza:", "Polizza n.", "n. polizza", "N. Polizza",
"numero polizza", "Numero Polizza",
"assicurativa", "assicurazione",
"contratto assicurativo", "polizza fideiussoria", "fideiussione"]),
# Polizza – formato generico (score basso, richiede context)
_r("POLIZZA_ASSICURATIVA", "polizza_alt",
r"\b[A-Z0-9]{2,5}[\-/\.][A-Z0-9]{4,15}(?:[\-/\.][A-Z0-9]{2,10}){0,2}\b", 0.45,
["polizza", "Polizza", "n. polizza", "numero polizza",
"assicurativa", "fideiussoria", "fideiussione",
"contratto assicurativo"]),
# CPV – Common Procurement Vocabulary
_r("CPV", "cpv",
r"\b\d{8}-\d\b", 0.92,
["CPV", "cpv", "Cpv", "CPV:", "cpv:", "codice CPV", "Codice CPV",
"vocabolario comune appalti", "Vocabolario Comune degli Appalti",
"categoria merceologica", "oggetto della fornitura",
"classificazione CPV"]),
# NUTS – area territoriale
_r("NUTS", "nuts",
r"\bIT[A-Z0-9]{1,4}\b", 0.80,
["NUTS", "nuts", "NUTS:", "nuts:", "codice NUTS", "Codice NUTS",
"NUTS2", "NUTS3", "nuts2", "nuts3",
"area geografica", "territorio", "area NUTS",
"localizzazione geografica"]),
# ATECO 2007
_r("ATECO", "ateco",
r"\b\d{2}\.\d{2}(?:\.\d{1,2})?\b", 0.60,
["ATECO", "ateco", "Ateco", "ATECO:", "codice ATECO", "Codice ATECO",
"attività economica", "Attività Economica",
"classificazione ATECO", "codice attività",
"settore ATECO", "categoria ATECO"]),
# Percentuale di ribasso
_r("PERCENTUALE_RIBASSO", "ribasso",
r"\b\d{1,2}(?:,\d{1,4})?\s*%", 0.55,
["ribasso", "Ribasso", "al ribasso",
"ribasso d'asta", "ribasso offerto",
"rialzo", "percentuale di ribasso",
"offerta economica", "sconto", "aggiudicazione",
"percentuale offerta"]),
# Numero protocollo PA
_r("NUMERO_PROTOCOLLO", "protocollo",
r"(?:prot(?:ocollo)?\.?\s*(?:n\.?)?\s*)\d{4,8}(?:[/\-]\d{2,4})?", 0.85,
["protocollo", "Protocollo", "prot.", "Prot.", "PROT.",
"n. prot", "N. Prot", "N.Prot",
"numero protocollo", "Numero Protocollo",
"repertorio", "fascicolo", "prot. n.", "Prot. n."]),
# Atto amministrativo (determinazione / delibera / decreto)
_r("ATTO_AMMINISTRATIVO", "atto",
r"(?:det(?:erminazione)?\.?|delib(?:era)?\.?|decreto|d\.g\.?|d\.d\.?)"
r"\s*(?:n\.?)?\s*\d{1,6}(?:[/\-]\d{2,4})?", 0.78,
["determinazione", "Determinazione", "det.",
"delibera", "Delibera", "delib.",
"decreto", "Decreto",
"d.g.", "D.G.", "d.d.", "D.D.",
"atto", "Atto", "provvedimento", "Provvedimento",
"disposizione", "ordinanza", "Ordinanza"]),
# Codice ANAC operatore economico
_r("CODICE_ANAC", "anac",
r"\bIT-\d{11}\b", 0.92,
["codice ANAC", "Codice ANAC", "codice anac",
"BDNCP", "bdncp", "banca dati ANAC",
"operatore economico", "Operatore Economico",
"attestazione ANAC", "white list", "White List",
"iscrizione ANAC"]),
# Numero lotto gara
_r("LOTTO_GARA", "lotto",
r"\b(?:lotto|lot\.?)\s*(?:n\.?)?\s*\d{1,3}[a-z]?\b", 0.75,
["lotto", "Lotto", "LOTTO",
"lotto n.", "Lotto n.", "lotto n°",
"lotto:", "Lotto:", "sub-lotto",
"lotti", "Lotti", "suddivisione in lotti",
"aggiudicazione per lotti"]),
# SIOGG
_r("SIOGG", "siogg",
r"\bSOGG-?[A-Z0-9]{8,12}\b", 0.88,
["SIOGG", "siogg", "osservatorio", "Osservatorio",
"contratti pubblici", "Contratti Pubblici",
"osservatorio contratti"]),
# CF aziendale – 11 cifre con context "C.F." (disambigua da P.IVA)
_r("CODICE_FISCALE", "cf_azienda",
r"\b\d{11}\b", 0.75,
["C.F.", "c.f.", "CF", "cf", "C.F.:", "c.f.:", "CF:",
"codice fiscale", "Codice Fiscale",
"codice fiscale azienda", "codice fiscale impresa",
"codice fiscale società"]),
# Forme societarie – nome (1-4 parole capitalizzate) + sigla giuridica
_r("SOCIETA", "societa",
r"\b(?:[A-Z][\w&\-']*\s+){1,4}"
r"(?:"
r"S\.?\s*r\.?\s*l\.?(?:\s*[Ss]\.?)?|"
r"S\.?\s*p\.?\s*[Aa]\.?|"
r"S\.?\s*a\.?\s*p\.?\s*[Aa]\.?|"
r"S\.?\s*n\.?\s*c\.?|"
r"S\.?\s*a\.?\s*s\.?|"
r"S\.?\s*s\.?|"
r"S\.?\s*c\.?\s*a\.?\s*r\.?\s*l\.?|"
r"Soc(?:\.|ietà)?\s+[Cc]oop(?:\.|erativa)?(?:\s+a\s+r\.?\s*l\.?)?|"
r"Cooperativa(?:\s+Sociale)?|"
r"Onlus|ONLUS|"
r"E\.?\s*T\.?\s*S\.?|"
r"A\.?\s*P\.?\s*S\.?|"
r"O\.?\s*N\.?\s*G\.?|"
r"Lda\.?|Ltd\.?|GmbH|S\.?\s*A\.?|Inc\.?"
r")\b\.?", 0.85,
["società", "Società", "SOCIETÀ",
"impresa", "Impresa", "ditta", "Ditta", "azienda", "Azienda",
"ragione sociale", "Ragione Sociale",
"denominazione", "Denominazione",
"operatore economico", "Operatore Economico",
"subappaltatore", "appaltatore", "aggiudicatario",
"banca", "Banca", "istituto", "compagnia", "Compagnia",
"fornitore", "Fornitore", "concessionario"]),
# Iscrizione Albo professionale
_r("ISCRIZIONE_ALBO", "albo",
r"(?:[Aa]lbo\s+(?:degli?\s+)?\w+(?:\s+(?:di|della|del)\s+\w+)?"
r"(?:\s+(?:di|della|del)\s+\w+)?)\s*(?:al|n\.?)?\s*\d+(?:/[A-Z])?", 0.80,
["albo", "Albo", "iscrizione", "Iscrizione",
"iscritto", "iscritta",
"albo professionale", "Albo Professionale",
"ordine professionale"]),
]
# ---------------------------------------------------------------------------
# POST_BOOST_PATTERNS – validazione fullmatch (score +0.30 se match esatto)
# ---------------------------------------------------------------------------
POST_BOOST_PATTERNS: dict[str, _re.Pattern] = {
"NUMERIC": _re.compile(r"^\d{4,7}$"),
"CIG": _re.compile(r"^(?:\d{7}[0-9A-F]{3}|[A-Z][0-9A-F]{9})$"),
"CUP": _re.compile(r"^[A-Z]\d{2}[A-Z][A-Z0-9]{2}\d{6}[A-Z0-9]{3}$"),
"REA": _re.compile(r"^[A-Z]{2}[\s\-/\.]\d{4,7}$"),
"CPV": _re.compile(r"^\d{8}-\d$"),
"NUTS": _re.compile(r"^IT[A-Z0-9]{1,4}$"),
"ATECO": _re.compile(r"^\d{2}\.\d{2}(?:\.\d{1,2})?$"),
"CODICE_ANAC": _re.compile(r"^IT-\d{11}$"),
"SIOGG": _re.compile(r"^SOGG-?[A-Z0-9]{8,12}$"),
"LOTTO_GARA": _re.compile(r"^(?:lotto|lot\.?)\s*(?:n\.?)?\s*\d{1,3}[a-z]?$",
_re.IGNORECASE),
"POLIZZA_ASSICURATIVA": _re.compile(r"^[A-Z]{2,5}-\d{4}-[A-Z]{2}-\d{6,12}$"),
"PEC": _re.compile(
r"^[\w.\-]+@[\w.\-]*(?:pec|postacert|legalmail|pecmail|"
r"sicurezzapostale|registerpec|ticertifica)[\w.\-]*\.\w+$", _re.IGNORECASE),
"CODICE_FISCALE": _re.compile(r"^[A-Z]{6}\d{2}[A-Z]\d{2}[A-Z]\d{3}[A-Z]$",
_re.IGNORECASE),
"PARTITA_IVA": _re.compile(r"^(IT\s*)?\d{11}$", _re.IGNORECASE),
"IBAN_CODE": _re.compile(r"^IT\d{2}[A-Z]\d{10}[A-Z0-9]{12}$", _re.IGNORECASE),
"BIC_SWIFT": _re.compile(
r"^[A-Z]{4}(?:IT|DE|FR|ES|GB|CH|NL|BE|AT|PT|GR|LU|IE|FI|SE|DK|NO|PL)"
r"[A-Z0-9]{2}(?:[A-Z0-9]{3})?$"),
"CREDIT_CARD": _re.compile(
r"^(?:4\d{3}|5[1-5]\d{2}|3[47]\d{2}|6(?:011|5\d{2}))"
r"[\s\-]?\d{4}[\s\-]?\d{4}[\s\-]?\d{3,4}$"),
"IP_ADDRESS": _re.compile(
r"^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$"),
"MAC": _re.compile(r"^(?:[0-9A-Fa-f]{2}[:\-]){5}[0-9A-Fa-f]{2}$"),
"TARGA_VEICOLO": _re.compile(
r"^(?:[A-Z]{2}\d{3}[A-Z]{2}|[A-Z]{2}\d{4}[A-Z]|"
r"(?:CC|EI|EE|RM|VF|CRI|SCC|CD)\s*\d{3,5})$", _re.IGNORECASE),
"NUMERO_PROTOCOLLO": _re.compile(
r"^prot(?:ocollo)?\.?\s*(?:n\.?)?\s*\d{4,8}(?:[/\-]\d{2,4})?$", _re.IGNORECASE),
}