# ============================================================================= # Job·Ka — Groupe KA # Auteur : Simon-Pierre Boucher # Contact : contact@spboucher.ai # Fichier : jobka/regions.py # Rôle : Région administrative du Québec (17 régions) depuis la ville — # répertoire MAMH embarqué (data/regions-qc.json) + arrondissements # Créé : 2026-08-19 Modifié : 2026-08-19 # ============================================================================= """Dérivation de la région administrative (17 régions du Québec). Source : Répertoire des municipalités du MAMH (données ouvertes, colonne `regadm`), figé dans ``data/regions-qc.json`` (~1 260 entrées : municipalités + arrondissements/quartiers fréquents dans les libellés d'offres). Clé de recherche : nom de ville minuscules sans accents. Ville inconnue -> "" — jamais de région inventée. """ from __future__ import annotations import json from functools import lru_cache from pathlib import Path from .normalize import canonical_city, strip_accents _DATA_PATH = Path(__file__).resolve().parent.parent / "data" / "regions-qc.json" # Les 17 régions administratives (référence pour validation/affichage) REGIONS_QC = ( "Abitibi-Témiscamingue", "Bas-Saint-Laurent", "Capitale-Nationale", "Centre-du-Québec", "Chaudière-Appalaches", "Côte-Nord", "Estrie", "Gaspésie–Îles-de-la-Madeleine", "Lanaudière", "Laurentides", "Laval", "Mauricie", "Montérégie", "Montréal", "Nord-du-Québec", "Outaouais", "Saguenay–Lac-Saint-Jean", ) @lru_cache(maxsize=1) def _mapping() -> dict[str, str]: try: return json.loads(_DATA_PATH.read_text(encoding="utf-8")) except (OSError, ValueError): return {} def _key(city: str) -> str: return " ".join(strip_accents((city or "").lower()).split()) def city_from_slug_tokens(tokens: list[str]) -> str: """Plus long préfixe de `tokens` (segments d'un slug d'URL) qui forme une municipalité québécoise connue — résout « Pointe-Claire-Analyste-… » où ville et titre partagent le même séparateur « - ». Retourne la ville reconstituée (« Pointe-Claire »), ou "" si aucun préfixe ne correspond. """ from .normalize import _QC_CITIES # table des libellés fréquents table = _mapping() for n in range(min(len(tokens), 5), 0, -1): raw = "-".join(t for t in tokens[:n] if t) k = _key(raw) k2 = k.replace("st-", "saint-").replace("ste-", "sainte-") if k in table or k2 in table or k in _QC_CITIES or k2 in _QC_CITIES: return raw return "" def region_for_city(city: str) -> str: """Ville -> région administrative (« Montérégie »…), ou "" si inconnue. La ville est d'abord canonicalisée (« Quebec City » -> « Québec ») ; les préfixes de type « Ville de » sont tolérés. """ if not city: return "" table = _mapping() for candidate in (canonical_city(city), city): k = _key(candidate) if not k: continue if k in table: return table[k] # « ville de sherbrooke », « st-jerome » (st- = saint-) k2 = k.removeprefix("ville de ").replace("st-", "saint-") \ .replace("ste-", "sainte-") if k2 in table: return table[k2] return ""