Ramener les ligatures « œ » et « æ » à « oe » et « ae »

L'Œuvre de Zola, que la BnF écrit avec la ligature, était introuvable à
qui tape « oeuvre » : NFD sépare les accents mais laisse les ligatures.

Table explicite plutôt que NFKD, qui aurait aussi transformé les exposants,
les chiffres romains et les espaces insécables. Une normalisation de
recherche doit rester prévisible.

Sept colonnes normalisées en dépendent, dont cinq portent une unicité. Le
rattrapage au démarrage est donc étendu aux envies, séries, revues et
numéros — qui ne calculaient leurs formes qu'à l'écriture — et refuse toute
collision AVANT d'écrire : sinon l'exception tomberait au démarrage et le
serveur ne se lancerait plus.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mathieu
2026-08-19 22:25:59 +02:00
co-authored by Claude Opus 5
parent ca0a9dc18c
commit b97cf33494
7 changed files with 293 additions and 36 deletions
@@ -27,6 +27,18 @@ public static class NormalisationTexte
/// La ponctuation devient une espace plutôt que de disparaître : « P.F. Hamilton » doit
/// donner trois mots (<c>p f hamilton</c>) et non un seul (<c>pf hamilton</c>), sans quoi
/// le rapprochement par initiales serait impossible.
/// <para>
/// Les <b>ligatures</b> <c>œ</c> et <c>æ</c> sont décomposées en <c>oe</c> et <c>ae</c>.
/// ⚠️ Ce n'est pas ce que fait la décomposition NFD, qui sépare les accents mais laisse les
/// ligatures intactes : sans ce traitement explicite, <i>L'Œuvre</i> de Zola — que la BnF
/// écrit avec la ligature — resterait introuvable à qui tape « oeuvre » au clavier.
/// </para>
/// <para>
/// Le choix s'est porté sur une table explicite plutôt que sur NFKD, qui aurait fait bien
/// davantage : « ² » → « 2 », « Ⅻ » → « XII », les espaces insécables, les formes de
/// présentation. Une normalisation de recherche doit rester prévisible ; on ne défait ici que
/// ce dont on a constaté le besoin.
/// </para>
/// </remarks>
public static string Normaliser(string? brut)
{
@@ -47,6 +59,18 @@ public static class NormalisationTexte
continue; // Accent détaché par la décomposition.
}
if (Ligature(c) is { } lettres)
{
if (espaceEnAttente && sortie.Length > 0)
{
sortie.Append(' ');
}
espaceEnAttente = false;
sortie.Append(lettres);
continue;
}
if (char.IsLetterOrDigit(c))
{
if (espaceEnAttente && sortie.Length > 0)
@@ -66,6 +90,21 @@ public static class NormalisationTexte
return sortie.ToString().Normalize(NormalizationForm.FormC);
}
/// <summary>
/// Développement d'une ligature, ou <c>null</c> si le caractère n'en est pas une.
/// </summary>
/// <remarks>
/// Volontairement limité à <c>œ</c> et <c>æ</c>, seules ligatures courantes du français.
/// Les ligatures typographiques de présentation (<c>fi</c>, <c>fl</c>) ne sont pas traitées :
/// elles n'apparaissent pas dans les catalogues, et rien n'a montré le besoin.
/// </remarks>
private static string? Ligature(char c) => c switch
{
'œ' or 'Œ' => "oe",
'æ' or 'Æ' => "ae",
_ => null,
};
/// <summary>Mots de la forme normalisée, sans mot vide.</summary>
public static string[] Mots(string? brut)
{