SPB Git

Repository Public

csv.ts 2.0 KB 42 lines typescript

1// UQO Éval — Métré : analyseur CSV minimal (RFC 4180, guillemets, séparateur , ou ;). Module PUR.2export function parseCsv(text: string, opts: { delimiter?: "," | ";" | "\t"; maxRows?: number } = {}): { header: string[]; rows: string[][] } {3  const src = text.replace(/^/, "");4  const delim = opts.delimiter ?? detectDelimiter(src);5  const rows: string[][] = [];6  let row: string[] = [], field = "", q = false;7  for (let i = 0; i < src.length; i++) {8    const c = src[i];9    if (q) {10      if (c === '"') { if (src[i + 1] === '"') { field += '"'; i++; } else q = false; }11      else field += c;12    } else if (c === '"') q = true;13    else if (c === delim) { row.push(field); field = ""; }14    else if (c === "\n" || c === "\r") { if (c === "\r" && src[i + 1] === "\n") i++; row.push(field); field = ""; if (row.some((x) => x !== "")) rows.push(row); row = []; if (opts.maxRows && rows.length > opts.maxRows) break; }15    else field += c;16  }17  if (field !== "" || row.length) { row.push(field); if (row.some((x) => x !== "")) rows.push(row); }18  const header = (rows.shift() ?? []).map((h) => h.trim());19  return { header, rows };20}2122export function detectDelimiter(text: string): "," | ";" | "\t" {23  const first = text.split(/\r?\n/, 1)[0] ?? "";24  const c = (first.match(/,/g) ?? []).length, s = (first.match(/;/g) ?? []).length, t = (first.match(/\t/g) ?? []).length;25  return t > c && t > s ? "\t" : s > c ? ";" : ",";26}2728/** Nombre depuis une chaîne FR/EN (« 1 234,56 $ », "1,234.56"). */29export function parseNumber(s: string | undefined | null): number | null {30  if (s == null) return null;31  let t = String(s).replace(/[$\s ]/g, "").trim();32  if (!t) return null;33  if (/,\d{1,2}$/.test(t) && !/\.\d/.test(t)) t = t.replace(/\./g, "").replace(",", ".");34  else t = t.replace(/,/g, "");35  const n = Number(t);36  return Number.isFinite(n) ? n : null;37}3839export function normHeader(h: string): string {40  return h.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");41}42
Files main
Menu

Theme