using System.Text.RegularExpressions; namespace MaBibli.Api.Services.Isbn; /// /// Nettoyage de la ponctuation ISBD des champs Dublin Core de la BnF. /// /// /// Les champs BnF ne sont pas exploitables bruts. Règles validées le 2026-08-17 (CLAUDE.md) : /// /// dc:title : Germinal / Émile Zola ; préface…Germinal /// dc:creator : Zola, Émile (1840-1902). Auteur du texteÉmile Zola /// dc:publisher : le Livre de poche (Paris)le Livre de poche /// /// Les valeurs déjà propres doivent traverser ces règles inchangées. /// public static partial class NettoyageIsbd { [GeneratedRegex(@"\s*\([^)]*\)")] private static partial Regex Parentheses(); [GeneratedRegex(@"\s*\([^)]*\)\s*$")] private static partial Regex ParenthesesFinales(); /// /// Titre : couper à la première mention de responsabilité (« / »). /// public static string? Titre(string? brut) { var s = brut?.Trim(); if (string.IsNullOrEmpty(s)) { return null; } var i = s.IndexOf(" / ", StringComparison.Ordinal); if (i >= 0) { s = s[..i]; } s = s.Trim(); return s.Length == 0 ? null : s; } /// /// Auteur : retirer les dates entre parenthèses, le rôle qui suit le point, /// puis inverser « Nom, Prénom » en « Prénom Nom ». /// public static string? Auteur(string? brut) { var s = brut?.Trim(); if (string.IsNullOrEmpty(s)) { return null; } // 1. Dates de vie et autres qualificatifs entre parenthèses : (1840-1902), (1932-....) s = Parentheses().Replace(s, string.Empty).Trim(); // 2. Rôle après le point : « . Auteur du texte », « . Préfacier ». var pointRole = IndexDuPointDeRole(s); if (pointRole >= 0) { s = s[..pointRole]; } s = RetirerPonctuationFinale(s); // 3. Inversion « Nom, Prénom » → « Prénom Nom » (sur la première virgule seulement). var virgule = s.IndexOf(", ", StringComparison.Ordinal); if (virgule > 0) { var nom = s[..virgule].Trim(); var prenom = s[(virgule + 2)..].Trim(); if (nom.Length > 0 && prenom.Length > 0) { s = $"{prenom} {nom}"; } } s = s.Trim(); return s.Length == 0 ? null : s; } /// /// Éditeur : retirer la ville entre parenthèses en fin de chaîne. /// public static string? Editeur(string? brut) { var s = brut?.Trim(); if (string.IsNullOrEmpty(s)) { return null; } s = ParenthesesFinales().Replace(s, string.Empty).Trim(); return s.Length == 0 ? null : s; } /// /// Retire les virgules et espaces de fin, et le point final sauf s'il appartient /// à une initiale (« Cormen, Thomas H. » doit garder son point). /// private static string RetirerPonctuationFinale(string s) { s = s.TrimEnd(' ', ','); while (s.EndsWith('.')) { var i = s.Length - 1; var estInitiale = i >= 1 && char.IsUpper(s[i - 1]) && (i == 1 || s[i - 2] == ' ' || s[i - 2] == '-' || s[i - 2] == '\''); if (estInitiale) { break; } s = s[..^1].TrimEnd(' ', ','); } return s; } /// /// Position du point qui introduit le rôle, ou -1. /// /// /// Un point suivi d'une espace sépare le rôle du nom. On ignore les points d'initiales /// (« Cormen, Thomas H. Auteur ») : un point précédé d'une majuscule isolée n'est pas /// un séparateur de rôle. /// private static int IndexDuPointDeRole(string s) { for (var i = 0; i < s.Length - 1; i++) { if (s[i] != '.' || s[i + 1] != ' ') { continue; } var estInitiale = i >= 1 && char.IsUpper(s[i - 1]) && (i == 1 || s[i - 2] == ' ' || s[i - 2] == '-' || s[i - 2] == '\''); if (!estInitiale) { return i; } } return -1; } }