feat(detect): F3 capture du nom après label "Nom usuel :"

Le pipeline ne reconnaissait pas le label "Nom usuel :" — utilisé dans
certains comptes-rendus type BACTERIO. Ajout d'une regex dédiée
RE_EXTRACT_NOM_USUEL qui :

1. Trouve "Nom usuel :" en début de ligne
2. Skippe les lignes qui ne commencent pas par une lettre majuscule
   (date au format DD/MM/YYYY, placeholders entre crochets, lignes vides)
3. Capture le premier token en MAJUSCULES ≥4 chars

Cas couvert : BACTERIO 23232115 contient
    SIMONET Marie lise
    Nom usuel :
    14/03/1985
    OYARCABAL

OYARCABAL est ainsi extrait avec contexte "high" (champ DPI structuré
quasi-certain) et masqué.

Test unitaire rapide validé sur l'exemple ci-dessus.

Reste à faire : F2 (SIMONET — pattern NAME+PRENOM+PRENOM sans label) — non
trivial sans label, à implémenter avec heuristique contextuelle (top du doc,
etc.). Reporté.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 14:35:33 +02:00
parent 2f96f56432
commit 7b09b06065

View File

@@ -572,6 +572,17 @@ RE_EXTRACT_NOM_UTILISE = re.compile(
r"([A-ZÉÈÀÙÂÊÎÔÛÄËÏÖÜÇÑ][A-ZÉÈÀÙÂÊÎÔÛÄËÏÖÜÇÑa-zéèàùâêîôûäëïöüçñ\-\' ]+?)(?:\s*$)",
re.MULTILINE,
)
# F3 — capture du nom après "Nom usuel :" : le label peut être suivi de la
# date de naissance ou autres champs avant le nom. On skippe les lignes ne
# commençant pas par une majuscule (date au format DD/MM/YYYY, placeholders,
# champs vides) puis on capture le premier token en MAJUSCULES (≥4 chars).
# Cas typique BACTERIO : "Nom usuel :\n14/03/1985\nOYARCABAL".
RE_EXTRACT_NOM_USUEL = re.compile(
r"Nom\s+usuel\s*:\s*\n"
r"(?:[^A-ZÉÈÀÙÂÊÎÔÛÄËÏÖÜÇÑ\n][^\n]*\n)*"
r"([A-ZÉÈÀÙÂÊÎÔÛÄËÏÖÜÇÑ][A-ZÉÈÀÙÂÊÎÔÛÄËÏÖÜÇÑ\-\']{3,})",
re.MULTILINE,
)
RE_EXTRACT_PRENOM = re.compile(
r"Pr[ée]nom\s+(?:de\s+naissance|utilis[ée])\s*:\s*"
r"([A-ZÉÈÀÙÂÊÎÔÛÄËÏÖÜÇÑ][A-ZÉÈÀÙÂÊÎÔÛÄËÏÖÜÇÑa-zéèàùâêîôûäëïöüçñ\-\' ]+?)(?:\s*$)",
@@ -2140,6 +2151,9 @@ def _extract_document_names(full_text: str, cfg: Dict[str, Any]) -> Tuple[set, s
_add_tokens_force_all(m.group(1), "RE_EXTRACT_NOM_NAISSANCE", "high")
for m in RE_EXTRACT_NOM_UTILISE.finditer(full_text):
_add_tokens_force_all(m.group(1), "RE_EXTRACT_NOM_UTILISE", "high")
# F3 — "Nom usuel :" + ligne suivante (skip date intermédiaire)
for m in RE_EXTRACT_NOM_USUEL.finditer(full_text):
_add_tokens_force_all(m.group(1), "RE_EXTRACT_NOM_USUEL", "high")
for m in RE_EXTRACT_NOM_PRENOM.finditer(full_text):
_add_tokens_force_all(m.group(1), "RE_EXTRACT_NOM_PRENOM", "high")
for m in RE_EXTRACT_PRENOM.finditer(full_text):