namespace MaBibli.Shared.Isbn; /// /// Reconnaît qu'un terme de recherche est un code et non des mots, et donne les formes /// sous lesquelles le chercher dans le catalogue. /// /// /// /// Le geste visé : scanner un livre qu'on tient en main pour retrouver sa fiche. La douchette /// « tape » l'EAN-13 dans le champ de recherche, la caméra le pose de la même façon — mais la /// recherche du catalogue ne portait que sur le titre et les auteurs, donc ne rendait rien. /// /// /// ⚠️ Les deux formes d'ISBN sont indispensables, ici comme partout ailleurs dans le /// projet : un livre paru avant 2007 porte un ISBN-10 en base, alors qu'un code-barres se lit /// toujours en 13. Ne chercher qu'une forme ferait répondre « vous ne l'avez pas » à propos d'un /// livre posé sur l'étagère. /// /// /// ⚠️ Le seuil de huit chiffres n'est pas décoratif. Sans lui, chercher « 1984 » — un /// titre — remonterait tous les livres dont l'ISBN contient ces quatre chiffres, c'est-à-dire du /// bruit à la place d'une réponse. Aucun titre ne s'écrit avec huit chiffres d'affilée. /// /// public static class RechercheIsbn { /// En deçà, un terme numérique est un titre bien plus probablement qu'un code. private const int ChiffresMinimum = 8; /// /// Les formes à confronter à Livre.Isbn, ou null si le terme n'est pas un code. /// /// /// Un terme n'est un code que s'il ne contient rien d'autre que des chiffres, la /// ponctuation d'un ISBN (tirets, espaces, points) et l'éventuel X final : « Zola 1984 » /// reste une recherche de mots. /// public static IReadOnlyList? Formes(string? recherche) { if (string.IsNullOrWhiteSpace(recherche) || !QueDuCode(recherche)) { return null; } var chiffres = IsbnUtils.Normaliser(recherche); if (chiffres is null || chiffres.Length < ChiffresMinimum) { return null; } // La conversion 13 → 10 ne vaut que pour un ISBN-13 complet et valide ; sur un fragment, // elle n'a pas de sens et on s'en passe — la forme longue suffit alors. return IsbnUtils.TryConvertirEnIsbn10(chiffres, out var court) && court is not null ? [chiffres, court] : [chiffres]; } /// Vrai si le terme est un ISBN complet et valide — donc s'il désigne UNE édition. /// /// C'est ce qui autorise le catalogue à ouvrir directement la fiche quand un seul livre /// correspond : sur un fragment, le même résultat unique serait un hasard de frappe. /// public static bool EstCodeComplet(string? recherche) => QueDuCode(recherche) && IsbnUtils.EstValide(IsbnUtils.Normaliser(recherche)); private static bool QueDuCode(string? recherche) { if (string.IsNullOrWhiteSpace(recherche)) { return false; } foreach (var c in recherche) { if (!char.IsDigit(c) && c is not ('-' or ' ' or '.' or 'x' or 'X')) { return false; } } return true; } }