const P_VALUE_COLUMN_NAMES = new Set(['pvalue', 'pvalor']) const SCIENTIFIC_RE = /^\+?(\d+(?:[.,]\d*)?|[.,]\d+)(?:[eE]([+-]?\d+))?$/ export function isPValueColumn(column) { const normalized = String(column ?? '') .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') .toLowerCase() .replace(/[^a-z0-9]/g, '') return P_VALUE_COLUMN_NAMES.has(normalized) } export function parsePValue(value) { const raw = String(value ?? '').trim() const match = raw.match(SCIENTIFIC_RE) if (!match) return null let mantissa = Number(match[1].replace(',', '.')) let exponent = Number(match[2] || 0) if (!Number.isFinite(mantissa) || !Number.isInteger(exponent) || mantissa <= 0) return null while (mantissa >= 10) { mantissa /= 10 exponent += 1 } while (mantissa < 1) { mantissa *= 10 exponent -= 1 } return { mantissa, exponent, raw: raw.replace(',', '.') } } function formatExponent(exponent) { const sign = exponent < 0 ? '-' : '+' const digits = String(Math.abs(exponent)).padStart(2, '0') return `${sign}${digits}` } export function formatPValue(value) { const parsed = parsePValue(value) if (!parsed) return '-' if (parsed.exponent >= -4) { const numeric = Number(parsed.raw) return Number.isFinite(numeric) ? numeric.toFixed(4) : '-' } let mantissa = Number(parsed.mantissa.toFixed(2)) let exponent = parsed.exponent if (mantissa >= 10) { mantissa = 1 exponent += 1 } return `${mantissa.toFixed(2)}E${formatExponent(exponent)}` } export function comparePValues(left, right) { const leftParsed = parsePValue(left) const rightParsed = parsePValue(right) if (!leftParsed || !rightParsed) return null if (leftParsed.exponent !== rightParsed.exponent) { return leftParsed.exponent < rightParsed.exponent ? -1 : 1 } if (leftParsed.mantissa === rightParsed.mantissa) return 0 return leftParsed.mantissa < rightParsed.mantissa ? -1 : 1 }