From e2e2a7c8e379f8abd227832bca03337250d54f10 Mon Sep 17 00:00:00 2001 From: Domi31tls Date: Wed, 15 Apr 2026 14:10:34 +0200 Subject: [PATCH] =?UTF-8?q?fix(redact):=20masquer=20tokens=20coll=C3=A9s?= =?UTF-8?q?=20=C3=A0=20ponctuation=20("Douar,n=C3=A9cessitant")?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fuite détectée lors du QC batch 22 : le nom "Douar" était dans l'audit (NOM page 6) mais restait visible dans le PDF redacted_vector. Cause : dans get_text('words') le word était 'Douar,nécessitant' (virgule collée sans espace). _search_whole_word faisait un == strict après strip des ponctuations frontières, mais la virgule était au MILIEU — pas stripée. → aucun match → aucun rectangle → fuite. Fix : passe 2 dans _search_whole_word avec regex word-boundary sur le texte complet du word (pattern `(? --- anonymizer_core_refactored_onnx.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/anonymizer_core_refactored_onnx.py b/anonymizer_core_refactored_onnx.py index a1ff5b4..b595899 100644 --- a/anonymizer_core_refactored_onnx.py +++ b/anonymizer_core_refactored_onnx.py @@ -3929,15 +3929,42 @@ def _search_ocr_words(ocr_words: List[Tuple[str, float, float, float, float]], t def _search_whole_word(page, token: str) -> list: """Cherche un token comme mot entier (pas substring) via get_text('words'). Évite les faux positifs de page.search_for() qui fait du substring matching. - Gère les noms composés (JEAN-PIERRE) qui peuvent être splittés par le PDF.""" + Gère les noms composés (JEAN-PIERRE) qui peuvent être splittés par le PDF. + Gère aussi les tokens collés à de la ponctuation sans espace : "Douar,nécessitant" + (passe 2 avec regex word-boundary + bbox proportionnelle).""" rects = [] token_lower = token.lower().strip() words = page.get_text("words") + # Passe 1 : comparaison stricte après strip des ponctuations frontières. + # Couvre la majorité des cas normaux (mots bien séparés). for w in words: # w = (x0, y0, x1, y1, word, block_no, line_no, word_no) word_text = w[4].strip(".,;:!?()[]{}\"'«»-–—/\\") if word_text.lower() == token_lower: rects.append(fitz.Rect(w[0], w[1], w[2], w[3])) + # Passe 2 : token collé à d'autres mots via ponctuation interne. + # Ex: "Douar,nécessitant" où "Douar" doit être masqué. Le strip ci-dessus + # ne marche pas (la virgule est au milieu). Utiliser regex word-boundary + # sur le texte complet du word, calculer bbox proportionnelle. + if not rects and len(token_lower) >= 3: + pattern = re.compile( + r"(?