/
UzhvaD
/
Web_application_development_Course_work
Обзор
Документация
Войти
/
UzhvaD
/
Web_application_development_Course_work
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
js/utils.js
195 строк
7 KB
UzhvaD
create: style.css, app.js, database.js, scheduler.js, transforms.js, ui.js, utils.js
03 май 2026, 16:07
Верифицирован
03 май 2026, 16:07
b7726da
Код
Авторство
О чём код?
// ==================== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ==================== function escapeHtml(str) { if (!str) return ''; return String(str).replace(/[&<>]/g, m => { const map = { '&': '&', '<': '<', '>': '>' }; return map[m]; }); } function objectsToCsv(headers, data) { if (!headers.length) return ''; let csv = headers.join(',') + '\n'; data.forEach(row => { csv += headers.map(h => { let val = row[h] !== undefined ? row[h] : ''; if (typeof val === 'string' && val.includes(',')) val = `"${val}"`; return val; }).join(',') + '\n'; }); return csv; } function validateCSV(csvText) { if (!csvText || csvText.trim() === '') { return { valid: false, error: 'CSV данные пусты' }; } const lines = csvText.trim().split(/\r?\n/); if (lines.length < 2) { return { valid: false, error: 'Нужна строка заголовков + хотя бы одна строка данных' }; } const headers = lines[0].split(',').map(h => h.trim()); if (headers.length === 0) { return { valid: false, error: 'Нет заголовков' }; } const uniqueHeaders = new Set(headers); if (uniqueHeaders.size !== headers.length) { return { valid: false, error: 'Заголовки должны быть уникальными' }; } for (let i = 1; i < lines.length; i++) { const row = lines[i].split(','); if (row.length !== headers.length) { return { valid: false, error: `Строка ${i+1}: ${row.length} колонок, ожидается ${headers.length}` }; } } return { valid: true, headers: headers, rowCount: lines.length - 1 }; } function generateUniqueName(baseName, transformType, existingNames) { // Преобразуем transformType в человеко-читаемый вид const typeMap = { 'dedup': 'без_дубликатов', 'normalize': 'нормализовано', 'uppercase': 'верхний_регистр', 'fillna': 'заполнено' }; const typeText = typeMap[transformType] || transformType; let newName = `${baseName}_${typeText}`; // Ограничиваем длину имени (SQL и IndexedDB) if (newName.length > 50) { newName = newName.slice(0, 50); } // Проверяем на дубликаты как в Windows if (!existingNames || !existingNames.includes(newName)) { return newName; } let counter = 1; let finalName = `${newName}(${counter})`; while (existingNames.includes(finalName)) { counter++; finalName = `${newName}(${counter})`; } return finalName; } function formatDate(isoString) { if (!isoString) return ''; const date = new Date(isoString); return date.toLocaleString(); } function transliterate(name) { const ru = { 'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'e', 'ж': 'zh', 'з': 'z', 'и': 'i', 'й': 'y', 'к': 'k', 'л': 'l', 'м': 'm', 'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u', 'ф': 'f', 'х': 'h', 'ц': 'ts', 'ч': 'ch', 'ш': 'sh', 'щ': 'sch', 'ъ': '', 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu', 'я': 'ya' }; return name.toLowerCase().split('').map(char => { if (ru[char]) return ru[char]; if (/[a-z0-9_]/i.test(char)) return char; return '_'; }).join(''); } // Автоопределение разделителя CSV function detectDelimiter(line) { if (!line) return ','; // Приоритет: табуляция → точка с запятой → запятая if (line.includes('\t')) return '\t'; if (line.includes(';')) return ';'; return ','; } // Обновлённая функция csvToObjects с поддержкой разных разделителей function csvToObjects(csvText, delimiter = null) { const lines = csvText.trim().split(/\r?\n/); if (lines.length < 2) return { headers: [], data: [] }; // Автоопределение разделителя по первой строке const detectedDelimiter = delimiter || detectDelimiter(lines[0]); const headers = lines[0].split(detectedDelimiter).map(h => h.trim()); const data = []; for (let i = 1; i < lines.length; i++) { const values = lines[i].split(detectedDelimiter); const obj = {}; headers.forEach((h, idx) => { obj[h] = values[idx] !== undefined ? values[idx].trim() : ''; }); data.push(obj); } return { headers, data, delimiter: detectedDelimiter }; } // Обновлённая функция objectsToCsv с поддержкой разделителя function objectsToCsv(headers, data, delimiter = ',') { if (!headers.length) return ''; let csv = headers.join(delimiter) + '\n'; data.forEach(row => { csv += headers.map(h => { let val = row[h] !== undefined ? row[h] : ''; if (typeof val === 'string' && (val.includes(delimiter) || val.includes('"'))) { val = `"${val.replace(/"/g, '""')}"`; } return val; }).join(delimiter) + '\n'; }); return csv; } // Обновлённая функция validateCSV с поддержкой разных разделителей function validateCSV(csvText) { if (!csvText || csvText.trim() === '') { return { valid: false, error: 'CSV данные пусты' }; } const lines = csvText.trim().split(/\r?\n/); if (lines.length < 2) { return { valid: false, error: 'Нужна строка заголовков + хотя бы одна строка данных' }; } const delimiter = detectDelimiter(lines[0]); const headers = lines[0].split(delimiter).map(h => h.trim()); if (headers.length === 0) { return { valid: false, error: 'Нет заголовков' }; } const uniqueHeaders = new Set(headers); if (uniqueHeaders.size !== headers.length) { return { valid: false, error: 'Заголовки должны быть уникальными' }; } for (let i = 1; i < lines.length; i++) { const row = lines[i].split(delimiter); if (row.length !== headers.length) { return { valid: false, error: `Строка ${i+1}: ${row.length} колонок, ожидается ${headers.length} (разделитель: ${delimiter === '\t' ? '\\t' : delimiter})` }; } } return { valid: true, headers: headers, rowCount: lines.length - 1, delimiter: delimiter }; } window.escapeHtml = escapeHtml; window.csvToObjects = csvToObjects; window.objectsToCsv = objectsToCsv; window.validateCSV = validateCSV; window.generateUniqueName = generateUniqueName; window.formatDate = formatDate; window.detectDelimiter = detectDelimiter; // НОВАЯ