Gestion de bibliothèque personnelle auto-hébergée : catalogue, prêts, scan de code-barres, consultation hors-ligne. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
75 lines
3.6 KiB
C#
75 lines
3.6 KiB
C#
namespace MaBibli.Shared.Textes;
|
|
|
|
/// <summary>
|
|
/// Clé d'identification d'une <b>œuvre</b> à partir d'un titre, indépendamment de l'édition.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// C'est le rapprochement le moins mauvais dont on dispose, et il faut être clair sur ses limites.
|
|
/// <para>
|
|
/// <b>Pourquoi pas l'ISBN ?</b> Parce qu'il désigne une <i>édition</i>, pas une œuvre : le poche
|
|
/// de 1998, le grand format de 1991 et la réédition de 2015 portent trois ISBN différents pour le
|
|
/// même roman. Mesuré sur la bibliographie BnF de Bernard Werber : 183 notices de livres pour
|
|
/// 51 œuvres, chacune revenant en moyenne trois fois sous trois ISBN. Comparer les ISBN
|
|
/// répondrait donc « vous ne l'avez pas » à propos d'un livre posé sur l'étagère, ce qui est le
|
|
/// pire résultat possible pour une liste d'envies.
|
|
/// </para>
|
|
/// <para>
|
|
/// <b>Ce que la clé fait.</b> Elle coupe la mention de responsabilité ISBD (« <c> / </c> ») puis
|
|
/// le sous-titre (« <c> : </c> »), et met le reste à plat. C'est ce qui réunit
|
|
/// « Les thanatonautes », « Les thanatonautes : roman » et
|
|
/// « Les thanatonautes / Bernard Werber ».
|
|
/// </para>
|
|
/// <para>
|
|
/// <b>Ce qu'elle rate</b>, et qu'il ne faut pas prétendre autrement :
|
|
/// <list type="bullet">
|
|
/// <item>Deux œuvres distinctes partageant un titre principal sont confondues (« Œuvres »,
|
|
/// « Nouvelles »). Le risque est borné : la comparaison n'a lieu qu'<b>à auteur donné</b>.</item>
|
|
/// <item>Un tome n'est pas rapproché de son recueil : « Troisième humanité » et
|
|
/// « Troisième humanité. Tome 1 » restent deux lignes. Le point n'est pas coupé, faute de savoir
|
|
/// distinguer « Tome 1 » d'un titre qui contient légitimement un point.</item>
|
|
/// <item>Un titre retraduit ou changé au fil des rééditions n'est pas rapproché du tout.</item>
|
|
/// <item>Une œuvre possédée à l'intérieur d'une intégrale n'est pas repérée : l'intégrale a son
|
|
/// propre titre.</item>
|
|
/// </list>
|
|
/// Conséquence assumée : l'écran de bibliographie peut afficher comme « à découvrir » un livre
|
|
/// déjà présent sous un autre titre. Il ne fait donc que <b>griser</b> ce qu'il reconnaît, sans
|
|
/// jamais masquer une ligne — un faux négatif se voit et se corrige d'un coup d'œil, alors qu'une
|
|
/// ligne masquée à tort serait invisible.
|
|
/// </para>
|
|
/// </remarks>
|
|
public static class CleOeuvre
|
|
{
|
|
/// <summary>Sépare le titre de la mention de responsabilité : « Germinal / Émile Zola ».</summary>
|
|
private const string SeparateurResponsabilite = " / ";
|
|
|
|
/// <summary>Sépare le titre de son sous-titre : « Les thanatonautes : roman ».</summary>
|
|
private const string SeparateurSousTitre = " : ";
|
|
|
|
/// <summary>
|
|
/// Clé comparable d'un titre : « Les thanatonautes : roman » → <c>les thanatonautes</c>.
|
|
/// </summary>
|
|
public static string Cle(string? titre)
|
|
{
|
|
var s = titre?.Trim();
|
|
if (string.IsNullOrEmpty(s))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
s = Tronquer(s, SeparateurResponsabilite);
|
|
var sansSousTitre = Tronquer(s, SeparateurSousTitre);
|
|
|
|
// Un titre qui n'est QUE son sous-titre (« : roman ») ne doit pas se réduire à rien :
|
|
// mieux vaut alors garder la chaîne entière que produire une clé vide, qui se
|
|
// confondrait avec toutes les autres clés vides.
|
|
var retenu = NormalisationTexte.Normaliser(sansSousTitre);
|
|
return retenu.Length > 0 ? retenu : NormalisationTexte.Normaliser(s);
|
|
}
|
|
|
|
private static string Tronquer(string s, string separateur)
|
|
{
|
|
var i = s.IndexOf(separateur, StringComparison.Ordinal);
|
|
return i >= 0 ? s[..i].Trim() : s;
|
|
}
|
|
}
|