From f9fd5a7b8a30bf6d5871d7b41de4ad1cd052af3c Mon Sep 17 00:00:00 2001 From: host Date: Thu, 30 Jul 2026 16:50:44 +0300 Subject: [PATCH] Add utils.js with Excel reading, validation and normalization functions --- src/utils.js | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/utils.js diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..ccf428a --- /dev/null +++ b/src/utils.js @@ -0,0 +1,78 @@ +// utils.js +// Вспомогательные функции для работы с Excel, валидации и нормализации данных + +/** + * Читает файл Excel и возвращает массив листов. + * @param {File} file + * @returns {Promise>}>>} + */ +export async function readExcel(file) { + const data = await file.arrayBuffer(); + const wb = XLSX.read(data, { type: 'array' }); + return wb.SheetNames.map(name => ({ + name, + data: XLSX.utils.sheet_to_json(wb.Sheets[name], { header: 1, defval: '' }) + })); +} + +/** + * Проверка типа и размера файла. + * @param {File} file + * @returns {boolean} + */ +export function validateFile(file) { + const ext = file.name.slice(file.name.lastIndexOf('.')).toLowerCase(); + if (!['.xlsx', '.xls'].includes(ext)) { + alert(`Недопустимый тип файла: ${ext}`); + return false; + } + if (file.size === 0) { + alert('Файл пустой'); + return false; + } + return true; +} + +/** + * Нормализация номера ТС (замена латинских букв их русскими аналогами). + * @param {string} plate + * @returns {string} + */ +export function normalizePlate(plate) { + const map = {A:'\u0410',B:'\u0412',C:'\u0421',E:'\u0415',H:'\u041D',K:'\u041A',M:'\u041C',O:'\u041E',P:'\u0420',T:'\u0422',X:'\u0425',Y:'\u0423'}; + return plate.toUpperCase().replace(/[ABCEHKMOPTXY]/g, ch => map[ch] || ch); +} + +/** + * Приведение ФИО к единому регистру, замена Ё на Е. + * @param {string} name + * @returns {string} + */ +export function normalizeName(name) { + return name.toUpperCase().replace(/\u0401/g, '\u0415').trim(); +} + +/** + * Вычисление схожести строк (Levenshtein). + * @param {string} a + * @param {string} b + * @returns {number} коэффициент от 0 до 1 + */ +export function similarity(a, b) { + if (!a || !b) return 0; + const editDist = (s1, s2) => { + const dp = Array(s1.length + 1).fill().map(() => Array(s2.length + 1).fill(0)); + for (let i = 0; i <= s1.length; i++) dp[i][0] = i; + for (let j = 0; j <= s2.length; j++) dp[0][j] = j; + for (let i = 1; i <= s1.length; i++) { + for (let j = 1; j <= s2.length; j++) { + dp[i][j] = s1[i - 1] === s2[j - 1] + ? dp[i - 1][j - 1] + : Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1; + } + } + return dp[s1.length][s2.length]; + }; + const dist = editDist(a, b); + return 1 - dist / Math.max(a.length, b.length); +}