SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
10 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%
2.0 KB · 62 lines typescript
Raw Blame History
1/** Text normalisation helpers shared by entity resolution, search and connectors. */23export function slugify(input: string, maxLength = 96): string {4  const s = input5    .normalize('NFKD')6    .replace(/[̀-ͯ]/g, '')7    .toLowerCase()8    .replace(/&/g, ' and ')9    .replace(/[^a-z0-9]+/g, '-')10    .replace(/^-+|-+$/g, '');11  return s.length > maxLength ? s.slice(0, maxLength).replace(/-+$/g, '') : s;12}1314/** Aggressive normalisation for matching: lowercase, ASCII, punctuation removed, common noise words dropped. */15const NOISE = new Set(['the', 'a', 'an', 'of', 'and', '&', 'card', 'cards', 'lot', 'rare', 'mint', 'nm', 'lp', 'mp', 'hp', 'wow', 'look', 'nice', 'beautiful', 'gorgeous', 'pop', 'gem', 'mt', 'l@@k']);16export function normalizeForMatch(input: string): string {17  return input18    .normalize('NFKD')19    .replace(/[̀-ͯ]/g, '')20    .toLowerCase()21    .replace(/[#№]/g, ' ')22    .replace(/[^a-z0-9./\- ]+/g, ' ')23    .split(/\s+/)24    .filter((t) => t && !NOISE.has(t))25    .join(' ')26    .trim();27}2829export function tokens(input: string): string[] {30  return normalizeForMatch(input).split(' ').filter(Boolean);31}3233/** Jaccard similarity of token sets (0–1). */34export function jaccard(a: string, b: string): number {35  const A = new Set(tokens(a));36  const B = new Set(tokens(b));37  if (A.size === 0 && B.size === 0) return 1;38  let inter = 0;39  for (const t of A) if (B.has(t)) inter++;40  return inter / (A.size + B.size - inter);41}4243export function truncate(s: string, n: number): string {44  return s.length <= n ? s : `${s.slice(0, n - 1)}…`;45}4647export function compactWhitespace(s: string): string {48  return s.replace(/\s+/g, ' ').trim();49}5051/** Extract a 4-digit year plausible for collectibles (1800–current+1). */52export function extractYear(s: string): number | null {53  const now = new Date().getUTCFullYear() + 1;54  const m = s.match(/\b(1[89]\d{2}|20\d{2})\b/g);55  if (!m) return null;56  for (const y of m) {57    const n = Number(y);58    if (n >= 1800 && n <= now) return n;59  }60  return null;61}62