/
Coderdev
/
web-nodejs-labs
Обзор
Документация
Войти
/
Coderdev
/
web-nodejs-labs
Код
Запросы
0
Задачи
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
public/lab12/task3/index.html
283 строки
13 KB
Coderdev
1
26 май 2026, 12:10
26 май 2026, 12:10
d97058c
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ЛР12 — Тестер регулярных выражений</title> <link rel="preconnect" href="https://fonts.googleapis.com"> <link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap" rel="stylesheet"> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Space Mono','Courier New',monospace; background: #fafafa; color: #1a1a1a; font-size: 13px; line-height: 1.6; } .wrap { max-width: 720px; margin: 0 auto; padding: 40px 20px 60px; } h1 { font-size: 18px; font-weight: 700; text-transform: uppercase; letter-spacing: 2px; margin-bottom: 8px; } .subtitle { font-size: 11px; color: #999; margin-bottom: 32px; } h2 { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 3px; color: #999; margin-bottom: 16px; padding-bottom: 6px; border-bottom: 1px solid #e5e5e5; } .panel { background: #fff; padding: 24px; margin-bottom: 20px; border: 1px solid #e5e5e5; } label { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: #999; margin-bottom: 4px; } .field { margin-bottom: 16px; } input, select { font-family: inherit; font-size: 12px; width: 100%; height: 34px; padding: 4px 10px; border: 1px solid #ddd; background: #fafafa; color: #1a1a1a; outline: none; transition: border-color 0.15s; } input:focus { border-color: #1a1a1a; } .row { display: flex; gap: 12px; align-items: flex-end; margin-bottom: 16px; } .row > div { flex: 1; } .flag-row { display: flex; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; } .flag-item { display: flex; align-items: center; gap: 6px; font-size: 11px; cursor: pointer; } .flag-item input[type="checkbox"] { width: auto; height: auto; margin: 0; cursor: pointer; } button { font-family: inherit; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; cursor: pointer; padding: 8px 16px; border: 1px solid #1a1a1a; background: #1a1a1a; color: #fff; transition: 0.15s; white-space: nowrap; } button:hover { background: #444; } button.ghost { background: none; color: #1a1a1a; border-color: #ccc; } button.ghost:hover { border-color: #1a1a1a; } button.danger { background: #c0392b; border-color: #c0392b; color: #fff; } button.danger:hover { background: #a93226; } .results-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .results-header h2 { margin: 0; border: none; padding: 0; } .count-badge { font-size: 10px; color: #999; } .result-item { border: 1px solid #e5e5e5; background: #fff; margin-bottom: 10px; overflow: hidden; } .result-item.match { border-color: #27ae60; } .result-item.no-match { border-color: #c0392b; } .result-item.regex-error { border-color: #e67e22; } .result-header { display: flex; justify-content: space-between; align-items: center; padding: 8px 14px; font-size: 10px; } .result-item.match .result-header { background: #f0faf4; } .result-item.no-match .result-header { background: #fdf0f0; } .result-item.regex-error .result-header { background: #fffbf0; } .result-status { font-weight: 700; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; } .result-item.match .result-status { color: #27ae60; } .result-item.no-match .result-status { color: #c0392b; } .result-item.regex-error .result-status { color: #e67e22; } .result-time { color: #aaa; font-size: 10px; } .result-body { padding: 10px 14px; font-size: 11px; } .result-pattern { color: #888; margin-bottom: 6px; font-size: 10px; } .result-string { margin-bottom: 6px; } .result-string .label { color: #999; font-size: 10px; } .matches-list { margin-top: 8px; border-top: 1px solid #f0f0f0; padding-top: 8px; } .matches-label { font-size: 10px; color: #999; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 4px; } .match-chip { display: inline-block; margin: 2px 4px 2px 0; padding: 2px 8px; background: #27ae60; color: #fff; font-size: 11px; font-weight: 700; } .empty-results { text-align: center; padding: 40px 20px; color: #ccc; font-size: 12px; } .quick-examples { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; } .example-btn { font-family: inherit; font-size: 10px; font-weight: 400; cursor: pointer; padding: 3px 10px; border: 1px solid #ddd; background: #fafafa; color: #555; transition: 0.15s; } .example-btn:hover { border-color: #1a1a1a; color: #1a1a1a; background: #fff; } .back-link { margin-top: 40px; } .back-link a { font-size: 11px; color: #999; text-decoration: none; text-transform: uppercase; letter-spacing: 1px; } .back-link a:hover { color: #1a1a1a; } </style> </head> <body> <div class="wrap"> <h1>Тестер регулярных выражений</h1> <p class="subtitle">Проверка строки по шаблону. История сохраняется в LocalStorage.</p> <div class="panel"> <h2>Параметры проверки</h2> <div class="row"> <div> <label>Строка для проверки</label> <input id="inputStr" type="text" placeholder="Введите строку..." autocomplete="off"> </div> </div> <div class="row"> <div> <label>Шаблон регулярного выражения</label> <input id="inputPattern" type="text" placeholder="^\d+$" autocomplete="off"> </div> </div> <div> <label>Флаги</label> <div class="flag-row"> <label class="flag-item"><input type="checkbox" id="flagG"> <span>g — найти все совпадения</span></label> <label class="flag-item"><input type="checkbox" id="flagI"> <span>i — игнорировать регистр</span></label> <label class="flag-item"><input type="checkbox" id="flagM"> <span>m — многострочный режим</span></label> </div> </div> <div style="display:flex; gap:8px"> <button onclick="runTest()">Проверить</button> <button class="ghost" onclick="clearInput()">Очистить поля</button> </div> <div style="margin-top:16px"> <label>Быстрые примеры</label> <div class="quick-examples"> <button class="example-btn" onclick="loadExample('^\d+$', 'только цифры')">Только цифры</button> <button class="example-btn" onclick="loadExample('^[A-Za-z]+$', 'латиница')">Латиница</button> <button class="example-btn" onclick="loadExample('^[А-Яа-яЁё]+$', 'кириллица')">Кириллица</button> <button class="example-btn" onclick="loadExample('^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$', 'email')">Email</button> <button class="example-btn" onclick="loadExample('^\\w{4,10}$', 'логин')">Логин</button> <button class="example-btn" onclick="loadExample('^(ПИ|ИТ|БИ)-(202[0-5])-\\d{1,2}$', 'зачётка')">Зачётка</button> <button class="example-btn" onclick="loadExample('^(ПИ|ИТ|БИ|ЭС|МХ|ЮФ|ФК)-2[0-5]0[1-4]$', 'группа')">Группа</button> </div> </div> </div> <div class="results-header"> <h2>Результаты</h2> <div style="display:flex;gap:8px;align-items:center"> <span class="count-badge" id="countBadge"></span> <button class="danger" onclick="clearHistory()" style="font-size:10px;padding:4px 10px">Очистить историю</button> </div> </div> <div id="resultsList"> <div class="empty-results">История пуста — введите строку и шаблон, нажмите «Проверить»</div> </div> <div class="back-link"><a href="/lab12/">← К списку заданий</a></div> </div> <script> const STORAGE_KEY = 'lab12_regex_history'; function getHistory() { try { return JSON.parse(localStorage.getItem(STORAGE_KEY)) || []; } catch { return []; } } function saveHistory(history) { localStorage.setItem(STORAGE_KEY, JSON.stringify(history)); } function esc(str) { return String(str ?? '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); } function formatTime(iso) { const d = new Date(iso); return d.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit', second: '2-digit' }) + ' ' + d.toLocaleDateString('ru-RU', { day: '2-digit', month: '2-digit', year: 'numeric' }); } function renderHistory() { const history = getHistory(); const list = document.getElementById('resultsList'); const badge = document.getElementById('countBadge'); badge.textContent = history.length ? history.length + ' записей' : ''; if (!history.length) { list.innerHTML = '<div class="empty-results">История пуста — введите строку и шаблон, нажмите «Проверить»</div>'; return; } list.innerHTML = history.map(item => { if (item.type === 'regex-error') { return `<div class="result-item regex-error"> <div class="result-header"> <span class="result-status">Ошибка шаблона</span> <span class="result-time">${formatTime(item.time)}</span> </div> <div class="result-body"> <div class="result-pattern">Шаблон: <strong>/${esc(item.pattern)}/${esc(item.flags)}</strong></div> <div>${esc(item.error)}</div> </div> </div>`; } const matchesHtml = item.matches && item.matches.length ? `<div class="matches-list"> <div class="matches-label">Совпадения (${item.matches.length}):</div> ${item.matches.map(m => `<span class="match-chip">${esc(m)}</span>`).join('')} </div>` : ''; return `<div class="result-item ${item.type}"> <div class="result-header"> <span class="result-status">${item.type === 'match' ? 'Соответствует' : 'Не соответствует'}</span> <span class="result-time">${formatTime(item.time)}</span> </div> <div class="result-body"> <div class="result-pattern">Шаблон: <strong>/${esc(item.pattern)}/${esc(item.flags)}</strong></div> <div class="result-string"><span class="label">Строка: </span>${esc(item.str)}</div> ${matchesHtml} </div> </div>`; }).join(''); } function runTest() { const str = document.getElementById('inputStr').value; const pattern = document.getElementById('inputPattern').value.trim(); if (!pattern) { alert('Введите шаблон регулярного выражения'); return; } const flags = [ document.getElementById('flagG').checked ? 'g' : '', document.getElementById('flagI').checked ? 'i' : '', document.getElementById('flagM').checked ? 'm' : '', ].join(''); const history = getHistory(); const record = { str, pattern, flags, time: new Date().toISOString() }; try { const regexp = new RegExp(pattern, flags); const matches = str.match(regexp); if (matches) { record.type = 'match'; record.matches = flags.includes('g') ? matches : [matches[0]]; } else { record.type = 'no-match'; record.matches = []; } } catch (e) { record.type = 'regex-error'; record.error = e.message; } history.unshift(record); saveHistory(history); renderHistory(); } function clearHistory() { if (!confirm('Очистить всю историю?')) return; localStorage.removeItem(STORAGE_KEY); renderHistory(); } function clearInput() { document.getElementById('inputStr').value = ''; document.getElementById('inputPattern').value = ''; document.getElementById('flagG').checked = false; document.getElementById('flagI').checked = false; document.getElementById('flagM').checked = false; } function loadExample(pattern, str) { document.getElementById('inputPattern').value = pattern; document.getElementById('inputStr').value = str; } document.getElementById('inputStr').addEventListener('keydown', e => { if (e.key === 'Enter') runTest(); }); document.getElementById('inputPattern').addEventListener('keydown', e => { if (e.key === 'Enter') runTest(); }); renderHistory(); </script> </body> </html>