import { normalisiere, type Handout, type Inhalte } from './laden'; /** * Volltextsuche über die Handouts. * * Bewusst kein Suchindex und keine Bibliothek: Bei 52 Handouts ist ein * Durchlauf über alle Texte im Mikrosekundenbereich, und ein Suchindex wäre * eine zweite Wahrheit, die man pflegen müsste. */ export type Fundstueck = { handout: Handout; punkte: number; ausschnitt: string; }; /** Zerlegt die Eingabe in Wörter; Anführungszeichen halten eine Wortgruppe zusammen. */ export function suchbegriffe(eingabe: string): string[] { const treffer = eingabe.match(/"[^"]+"|\S+/g) ?? []; return treffer.map((t) => normalisiere(t.replace(/^"|"$/g, ''))).filter((t) => t.length > 1); } export function sucheHandouts(alle: Inhalte, eingabe: string, grenze = 30): Fundstueck[] { const begriffe = suchbegriffe(eingabe); if (begriffe.length === 0) return []; const gefunden: Fundstueck[] = []; for (const handout of alle.handouts) { const titel = normalisiere(`${handout.id} ${handout.titel}`); const worum = normalisiere(handout.worum); const merksatz = normalisiere(handout.merksatz); let punkte = 0; let alleEnthalten = true; for (const begriff of begriffe) { let treffer = 0; if (titel.includes(begriff)) treffer += 10; if (worum.includes(begriff)) treffer += 5; if (merksatz.includes(begriff)) treffer += 4; if (handout.suchtext.includes(begriff)) treffer += 1; if (treffer === 0) { alleEnthalten = false; break; } punkte += treffer; } if (!alleEnthalten) continue; gefunden.push({ handout, punkte, ausschnitt: ausschnittUm(handout, begriffe[0]!) }); } return gefunden .sort((a, b) => b.punkte - a.punkte || a.handout.id.localeCompare(b.handout.id, 'de-DE')) .slice(0, grenze); } /** * Ein Stück Text rund um den ersten Treffer, damit man in der Trefferliste * sieht, warum etwas gefunden wurde. */ function ausschnittUm(handout: Handout, begriff: string, laenge = 160): string { const stelle = handout.suchtext.indexOf(begriff); if (stelle === -1) return handout.worum; // Der normalisierte Text hat dieselbe Länge wie das Original, weil nur // kleingeschrieben und Leerraum vereinheitlicht wird – bis auf Umlaute. // Für einen Ausschnitt reicht das allemal. const roh = `${handout.id} ${handout.titel} ${handout.worum} ${handout.merksatz} ${handout.rumpf}` .replace(/\s+/g, ' ') .trim(); const mitte = Math.min(stelle, Math.max(0, roh.length - 1)); const von = Math.max(0, mitte - Math.floor(laenge / 3)); const bis = Math.min(roh.length, von + laenge); const teil = roh.slice(von, bis).trim(); return `${von > 0 ? '… ' : ''}${teil}${bis < roh.length ? ' …' : ''}`; }