const UNICODE_FRACTIONS: Record = { "½": 0.5, "⅓": 1/3, "⅔": 2/3, "¼": 0.25, "¾": 0.75, "⅕": 0.2, "⅖": 0.4, "⅗": 0.6, "⅘": 0.8, "⅙": 1/6, "⅚": 5/6, "⅛": 0.125, "⅜": 0.375, "⅝": 0.625, "⅞": 0.875, }; export function parseQuantity(v: string | number | undefined): string | undefined { if (v === undefined || v === "") return undefined; const s = String(v).trim(); if (!s) return undefined; if (UNICODE_FRACTIONS[s] !== undefined) return String(UNICODE_FRACTIONS[s]); for (const [frac, val] of Object.entries(UNICODE_FRACTIONS)) { if (s.endsWith(frac)) { const whole = s.slice(0, -frac.length).trim(); if (!whole) return String(val); const w = parseFloat(whole); if (!isNaN(w)) return String(w + val); } } const mixed = s.match(/^(\d+)\s+(\d+)\s*\/\s*(\d+)$/); if (mixed) { const den = parseInt(mixed[3]!); if (den !== 0) return String(parseInt(mixed[1]!) + parseInt(mixed[2]!) / den); } const slash = s.match(/^(\d+)\s*\/\s*(\d+)$/); if (slash) { const den = parseInt(slash[2]!); if (den !== 0) return String(parseInt(slash[1]!) / den); } const n = parseFloat(s); return isNaN(n) ? undefined : String(n); }