Skip to content

Instantly share code, notes, and snippets.

@ggorlen
Created January 26, 2026 18:59
Show Gist options
  • Select an option

  • Save ggorlen/b3f6002d5ce25b5f7f7afeffbcbcc4b1 to your computer and use it in GitHub Desktop.

Select an option

Save ggorlen/b3f6002d5ce25b5f7f7afeffbcbcc4b1 to your computer and use it in GitHub Desktop.
Number analyzer
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description" content="Number Analyzer" />
<meta name="color-scheme" content="dark light" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Number Analyzer</title>
<style>
body {
font-family: monospace;
padding: 2em;
max-width: 600px;
background-color: Canvas;
color: CanvasText;
}
textarea {
width: 100%;
height: 200px;
font-size: 14px;
line-height: 1.5;
padding: 10px;
box-sizing: border-box;
resize: vertical;
background-color: Canvas;
color: CanvasText;
border: 1px solid;
border-radius: 6px;
}
table {
width: 100%;
margin-top: 1em;
border-collapse: collapse;
table-layout: fixed;
}
th,
td {
padding: 6px 12px;
border: 1px solid;
text-align: left;
width: 50%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#highlighted-text {
white-space: pre-wrap;
margin-top: 10px;
padding: 10px;
border: 1px dashed;
border-radius: 6px;
display: none;
}
.highlighted {
background-color: #3e8d5e;
font-weight: bold;
border-radius: 2px;
color: CanvasText;
}
</style>
</head>
<body>
<h1>Number Analyzer</h1>
<textarea
id="input"
placeholder="Type numbers separated by anything..."
></textarea>
<table id="stats-table">
<tr>
<th>Sum</th>
<td id="sum">0</td>
</tr>
<tr>
<th>Count</th>
<td id="count">0</td>
</tr>
<tr>
<th>Average</th>
<td id="average">0</td>
</tr>
<tr>
<th>Median</th>
<td id="median">0</td>
</tr>
<tr>
<th>Min</th>
<td id="min">0</td>
</tr>
<tr>
<th>Max</th>
<td id="max">0</td>
</tr>
</table>
<div id="highlighted-text"></div>
<script>
// TODO: fix bug where '2.2.2.2 5' correctly ignores 2.2.2.2 but still highlights it
const textarea = document.getElementById("input");
const sumEl = document.getElementById("sum");
const countEl = document.getElementById("count");
const avgEl = document.getElementById("average");
const medianEl = document.getElementById("median");
const minEl = document.getElementById("min");
const maxEl = document.getElementById("max");
const highlightEl = document.getElementById("highlighted-text");
// Median helper
function median(arr) {
const sorted = [...arr].sort((a, b) => a - b);
if (sorted.length === 0) return 0;
const mid = Math.floor(sorted.length / 2);
return sorted.length % 2 === 0
? (sorted[mid - 1] + sorted[mid]) / 2
: sorted[mid];
}
// Parse numbers with strict rules
function parseNumbers(text) {
text = text.trim();
if (text === "") return [];
// Special delimiter case: entire input is digits+periods, more than 1 period
if (/^[\d.]+$/.test(text) && (text.match(/\./g) || []).length > 1) {
return text
.split(".")
.filter((s) => s !== "")
.map(Number);
}
// Otherwise, split by non-digit/non-dot/non-minus
const candidates = text.split(/[^0-9.\-]+/);
const numbers = [];
for (let c of candidates) {
if (c === "") continue;
// Trim single trailing dot (e.g., 2.2. -> 2.2)
if (c.endsWith(".") && (c.match(/\./g) || []).length === 2) {
c = c.slice(0, -1);
}
const dotCount = (c.match(/\./g) || []).length;
// Only accept numbers with 0 or 1 dot
if (dotCount <= 1 && !isNaN(Number(c))) {
numbers.push(Number(c));
}
// Multi-dot numbers ignored completely
}
return numbers;
}
// Highlight valid numbers only
function highlightValidNumbers(text) {
return text.replace(/-?\d*\.?\d+\.?/g, (m) => {
let candidate = m;
if (
candidate.endsWith(".") &&
(candidate.match(/\./g) || []).length === 2
) {
candidate = candidate.slice(0, -1);
}
const dotCount = (candidate.match(/\./g) || []).length;
if (dotCount <= 1 && !isNaN(Number(candidate))) {
return `<span class="highlighted">${candidate}</span>`;
}
return m; // ignore invalid numbers entirely
});
}
function updateStats() {
const text = textarea.value;
const numbers = parseNumbers(text);
if (numbers.length === 0) {
sumEl.textContent = 0;
countEl.textContent = 0;
avgEl.textContent = 0;
medianEl.textContent = 0;
minEl.textContent = 0;
maxEl.textContent = 0;
highlightEl.style.display = "none";
highlightEl.innerHTML = "";
return;
}
const sum = numbers.reduce((a, b) => a + b, 0);
const count = numbers.length;
const avg = sum / count;
const min = Math.min(...numbers);
const max = Math.max(...numbers);
const med = median(numbers);
sumEl.textContent = sum;
countEl.textContent = count;
avgEl.textContent = avg;
medianEl.textContent = med;
minEl.textContent = min;
maxEl.textContent = max;
const highlighted = highlightValidNumbers(text);
highlightEl.innerHTML = highlighted;
highlightEl.style.display = "block";
}
textarea.addEventListener("input", updateStats);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment