93 lines
3.5 KiB
Python
93 lines
3.5 KiB
Python
import os
|
||
import re
|
||
from pathlib import Path
|
||
from collections import defaultdict
|
||
|
||
from utils.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
|