🔍 Excel VLOOKUP 本地比對器
等同於 VLOOKUP(Value, Table, 2, FALSE) — 打字即時比對
0 筆
0 筆
📊 查找:0 筆
|
✅ 匹配:0 筆
|
❌ 未找到:0 筆
|
📐 對照表:0 筆
在上方貼入資料後,結果將即時顯示於此…
🔒 Zero-server · 100% In-Browser · No data ever leaves your device
// ── State ──────────────────────────────────────────────────────────────── let lookupMap = new Map(); let resultLines = []; // ── Helpers ────────────────────────────────────────────────────────────── /** * Parse textarea value into an array of non-empty trimmed lines. * Handles \r\n, \r, \n line endings. */ function parseLines(raw) { return raw .split(/\r\n|\r|\n/) .map(l => l.trim()) .filter(l => l.length > 0); } /** * Build a Map from the table textarea. * Each row is “Key\tValue”; if Tab is missing, the whole row is treated as * the Key and value is empty string. */ function buildMap(raw) { const map = new Map(); const lines = parseLines(raw); for (const line of lines) { const tabIdx = line.indexOf(‘\t’); if (tabIdx !== -1) { const key = line.substring(0, tabIdx).trim(); const val = line.substring(tabIdx + 1).trim(); if (key) map.set(key, val); } else { // Single-column row: key only, no value const key = line.trim(); if (key && !map.has(key)) map.set(key, ”); } } return map; } /** * Update the lookup counter badge. */ function updateCount(textareaId, countId) { const raw = document.getElementById(textareaId).value; const n = parseLines(raw).length; document.getElementById(countId).textContent = n + ‘ 筆’; return n; } // ── Core: VLOOKUP ──────────────────────────────────────────────────────── function runVlookup() { const rawA = document.getElementById(‘colA’).value; const rawB = document.getElementById(‘colB’).value; // Rebuild the map every time B changes (O(n) once) lookupMap = buildMap(rawB); // Update counters const nA = updateCount(‘colA’, ‘countA’); const nB = updateCount(‘colB’, ‘countB’); document.getElementById(‘statTable’).textContent = lookupMap.size; const lookupValues = parseLines(rawA); resultLines = []; let matchCount = 0; let naCount = 0; for (const val of lookupValues) { if (lookupMap.has(val)) { resultLines.push({ text: lookupMap.get(val), na: false }); matchCount++; } else { resultLines.push({ text: ‘#N/A’, na: true }); naCount++; } } // Render output renderOutput(lookupValues.length === 0); // Update stats bar const statsBar = document.getElementById(‘statsBar’); if (lookupValues.length > 0 || lookupMap.size > 0) { statsBar.classList.remove(‘hidden’); statsBar.classList.add(‘flex’); } else { statsBar.classList.add(‘hidden’); statsBar.classList.remove(‘flex’); } document.getElementById(‘statTotal’).textContent = lookupValues.length; document.getElementById(‘statMatch’).textContent = matchCount; document.getElementById(‘statNA’).textContent = naCount; } function renderOutput(isEmpty) { const output = document.getElementById(‘output’); if (isEmpty) { output.innerHTML = ‘在上方貼入資料後,結果將即時顯示於此…‘; return; } const fragment = document.createDocumentFragment(); for (const line of resultLines) { const div = document.createElement(‘div’); div.className = line.na ? ‘na-line’ : ‘match-line’; div.textContent = line.text; fragment.appendChild(div); } output.innerHTML = ”; output.appendChild(fragment); output.classList.remove(‘result-anim’); // Force reflow to restart animation void output.offsetWidth; output.classList.add(‘result-anim’); } // ── Copy ───────────────────────────────────────────────────────────────── async function copyResult() { if (resultLines.length === 0) return; const text = resultLines.map(l => l.text).join(‘\n’); try { await navigator.clipboard.writeText(text); } catch { // Fallback for environments without clipboard API const ta = document.createElement(‘textarea’); ta.value = text; ta.style.cssText = ‘position:fixed;opacity:0;top:0;left:0’; document.body.appendChild(ta); ta.select(); document.execCommand(‘copy’); document.body.removeChild(ta); } const btn = document.getElementById(‘copyBtn’); const originalHTML = btn.innerHTML; btn.innerHTML = ‘✅ 已複製!’; btn.classList.add(‘copy-success’, ‘bg-emerald-600’); btn.classList.remove(‘bg-emerald-500’); setTimeout(() => { btn.innerHTML = originalHTML; btn.classList.remove(‘copy-success’, ‘bg-emerald-600’); btn.classList.add(‘bg-emerald-500’); }, 1800); } // ── Clear helpers ──────────────────────────────────────────────────────── function clearField(textareaId, countId) { document.getElementById(textareaId).value = ”; document.getElementById(countId).textContent = ‘0 筆’; runVlookup(); } function clearAll() { [‘colA’, ‘colB’].forEach(id => document.getElementById(id).value = ”); [‘countA’, ‘countB’].forEach(id => document.getElementById(id).textContent = ‘0 筆’); lookupMap.clear(); resultLines = []; document.getElementById(‘output’).innerHTML = ‘在上方貼入資料後,結果將即時顯示於此…‘; document.getElementById(‘statsBar’).classList.add(‘hidden’); document.getElementById(‘statsBar’).classList.remove(‘flex’); } // ── Event listeners (real-time: “打字即顯示”) ────────────────────────── document.getElementById(‘colA’).addEventListener(‘input’, runVlookup); document.getElementById(‘colB’).addEventListener(‘input’, runVlookup); // Also handle paste events explicitly for instant response document.getElementById(‘colA’).addEventListener(‘paste’, () => setTimeout(runVlookup, 0)); document.getElementById(‘colB’).addEventListener(‘paste’, () => setTimeout(runVlookup, 0));

Comments