// Parses USA Swimming 2024-2028 single-age motivational standards from `pdftotext -raw` output. // Each event line: 6 girls times (B, BB, A, AA, AAA, AAAA), event, 6 boys times (AAAA, AAA, AA, A, BB, B). // Usage: node parse-swim.js -> JSON rows on stdout const fs = require('fs'); const secs = s => s.split(':').map(Number).reduce((a, b) => a * 60 + b, 0); const L = fs.readFileSync(process.argv[2], 'utf8').split(/\r?\n/); const LEVELS = ['B', 'BB', 'A', 'AA', 'AAA', 'AAAA']; const T = String.raw`(\d+:\d\d\.\d\d|\d+\.\d\d)\s*\*?`; const SEP = String.raw`\s*`; const lineRe = new RegExp('^' + Array(6).fill(T).join(SEP) + String.raw`\s+(\d+ (?:FR|BK|BR|FL|IM) (?:SCY|SCM|LCM))\s+` + Array(6).fill(T).join(SEP) + SEP + '$'); let age = null; const rows = []; for (const line of L) { const h = line.match(/^(\d+) Girls Event \d+ Boys/); if (h) { age = +h[1]; continue; } const m = line.match(lineRe); if (!m || age === null) continue; const g = m.slice(1, 7), event = m[7], b = m.slice(8, 14); LEVELS.forEach((lv, i) => rows.push({ age, event, level: lv, girls: g[i], boys: b[5 - i], girlsSeconds: Math.round(secs(g[i]) * 100) / 100, boysSeconds: Math.round(secs(b[5 - i]) * 100) / 100, gapPct: Math.round(1000 * (secs(g[i]) / secs(b[5 - i]) - 1)) / 10 })); } console.log(JSON.stringify(rows));