import os import re from pathlib import Path from collections import defaultdict from .config import ( CORPUS_DIR ) def composant_match(nom_composant, nom_dossier): """ Vérifie si le nom du composant correspond approximativement à un nom de dossier (lettres et chiffres dans le même ordre). """ def clean(s): return ''.join(c.lower() for c in s if c.isalnum()) cleaned_comp = clean(nom_composant) cleaned_dir = clean(nom_dossier) # Vérifie que chaque caractère de cleaned_comp est présent dans cleaned_dir dans le bon ordre it = iter(cleaned_dir) return all(c in it for c in cleaned_comp) def trouver_dossier_composant(nom_composant, base_path, prefixe): """ Parcourt les sous-répertoires de base_path et retourne celui qui correspond au composant. """ search_path = os.path.join(CORPUS_DIR, base_path) if not os.path.exists(search_path): return None for d in os.listdir(search_path): if os.path.isdir(os.path.join(search_path, d)): if composant_match(f"{prefixe}{nom_composant}", d): return os.path.join(base_path, d) return None def extraire_sections_par_mot_cle(fichier_markdown: Path) -> dict: """ Extrait les sections de niveau 3 uniquement dans la section '## Chaînes avec risque critique' du fichier Markdown, et les regroupe par mot-clé (ce qui se trouve entre '### ' et ' →'). Réduit chaque titre d’un niveau (#). """ with fichier_markdown.open(encoding="utf-8") as f: contenu = f.read() # Extraire uniquement la section '## Chaînes avec risque critique' match_section = re.search( r"## Chaînes avec risque critique(.*?)(?=\n## |\Z)", contenu, re.DOTALL ) if not match_section: return {} section_critique = match_section.group(1) # Extraire les mots-clés entre '### ' et ' →' mots_cles = set(re.findall(r"^### (.+?) →", section_critique, re.MULTILINE)) # Extraire tous les blocs de niveau 3 dans cette section uniquement blocs_sections = re.findall(r"(### .+?)(?=\n### |\n## |\Z)", section_critique, re.DOTALL) # Regrouper les blocs par mot-clé regroupement = defaultdict(list) for bloc in blocs_sections: match = re.match(r"### (.+?) →", bloc) if match: mot = match.group(1) if mot in mots_cles: # Réduction du niveau des titres bloc_modifie = re.sub(r"^###", "##", bloc, flags=re.MULTILINE) bloc_modifie = re.sub(r"^###", "##", bloc_modifie, flags=re.MULTILINE) regroupement[mot].append(bloc_modifie) return {mot: "\n\n".join(blocs) for mot, blocs in regroupement.items()} def nettoyer_texte_fr(texte: str) -> str: # Apostrophes droites -> typographiques texte = texte.replace("'", "’") # Guillemets droits -> guillemets français (avec espace fine insécable) texte = re.sub(r'"(.*?)"', r'« \1 »', texte) # Espaces fines insécables avant : ; ! ? texte = re.sub(r' (?=[:;!?])', '\u202F', texte) # Unités : espace insécable entre chiffre et unité texte = re.sub(r'(\d) (?=\w+)', lambda m: f"{m.group(1)}\u202F", texte) # Suppression des doubles espaces texte = re.sub(r' {2,}', ' ', texte) # Remplacement optionnel des tirets simples (optionnel) texte = texte.replace(" - ", " – ") # Nettoyage ponctuation multiple accidentelle texte = re.sub(r'\s+([.,;!?])', r'\1', texte) return texte