Как правильно обрабатывать объединённые ячейки?
По вводным: решил сделать бота в Telegram для более удобного пользования расписанием университета. (Забираю xlsx файл из сайта университета, распаршиваю его в bd.json)
Сейчас ситуация такая: возникла проблема, которую не могу решить: есть три массива all, sub1, sub2 в расписании присутсвует две подгруппы с разными парами, и общие пары для этих подгрупп, которые находятся в объединении ячеек). И сейчас общие пары кладутся в массив sub1 вместе с парами для первой подгруппы, в массив sub2 кладутся только пары для второй подгруппы.
Как бы хотелось:
- В all попадут общие пары
По вводным: в sub1 попадут только пары для первой подгруппы
По вводным: sub2 работает без перебоев - All исчезнет
Sub1 не изменится
По вводным: в sub2 попадут еще и общие пары
const axios = require('axios'); const cheerio = require('cheerio'); const XLSX = require('xlsx'); const PAGE_URL = 'https://schedule-cloud.cfuv.ru/index.php/s/DKNodfRxgf9c5Xc'; const DAYS = ['понедельник','вторник','среда','четверг','пятница', 'суббота']; const PARITY_ORDER = ['odd','even']; const ROOM_RX = /(?:аудитория|ауд)\.?\s*([0-9A-Za-zА-Яа-я]+)/i; const TEACHER_RX = /^(ст\.|доц\.|проф\.|ас\.|вак\.)/i; async function fetchSchedule() { // скачать XLSX const { data: html } = await axios.get(PAGE_URL); const $ = cheerio.load(html); const rel = $('a[href$=".xlsx"]').first().attr('href'); if (!rel) throw new Error('xlsx не найден'); const xlsxUrl = new URL(rel, PAGE_URL).href; const { data: buf } = await axios.get(xlsxUrl, { responseType: 'arraybuffer' }); // прочитать первый лист(т.к листы разделены по курсам) const wb = XLSX.read(buf, { type: 'buffer' }); const ws = wb.Sheets[wb.SheetNames[0]]; const rows = XLSX.utils.sheet_to_json(ws, { header: 1, defval: '' }); // найти блоки odd/even let hdr = -1, blocks = []; for (let i = 0; i < rows.length; i++) { const lc = rows[i].map(c => String(c).toLowerCase().trim()); const idxsDay = lc.reduce((a,v,i) => v === 'дни недели' ? a.concat(i) : a, []); if (idxsDay.length >= 2 && lc.includes('пара') && lc.includes('вид занятий')) { const found = []; for (let col of idxsDay) { const ci = lc.indexOf('пара', col+1); const ti = lc.indexOf('вид занятий', col+1); if (ci > col && ti > ci) found.push({ colDay: col, colPair: ci, colType: ti }); } if (found.length >= 2) { hdr = i; found.forEach((f, b) => { const start = f.colDay; const end = found[b+1]?.colDay ?? lc.length; blocks.push({ ...f, startCol:start, endColExcl:end, parity: b===0?'odd':'even' }); }); break; } } } if (hdr < 0) throw new Error('Не найдены блоки недель'); // строка с подгруппами let subg = hdr + 1; while (subg < rows.length && !rows[subg].some(c=>/\([12]\)$/.test(String(c).trim()))) subg++; if (subg >= rows.length) throw new Error('Не найдена строка подгрупп'); blocks.forEach(b => { b.subjCols = []; for (let i = b.startCol; i < b.endColExcl; i++) { const m = String(rows[subg][i]).trim().match(/\((\d)\)$/); if (m) b.subjCols.push({ idx:i, subgroup:m[1] }); } b.col1 = b.subjCols.find(x=>x.subgroup==='1').idx; b.col2 = b.subjCols.find(x=>x.subgroup==='2').idx; }); const slots = {}; const state = blocks.map(() => ({ day:null, pair:null })); for (let r = hdr+1; r < rows.length; r++) { const row = rows[r]; blocks.forEach((b,i) => { const d = String(row[b.colDay]||'').trim().toLowerCase(); const p = String(row[b.colPair]||'').trim(); if (DAYS.includes(d)) { state[i].day = d; state[i].pair = null; } if (/^[1-7]$/.test(p)) state[i].pair = +p; }); blocks.forEach((b,i) => { const { day, pair } = state[i]; if (!day || !pair) return; const rawType = String(row[b.colType]||'').trim().toUpperCase(); const type = ['ЛК','ПЗ'].includes(rawType) ? rawType : ''; [ {idx:b.col1, sub:'1'}, {idx:b.col2, sub:'2'} ].forEach(({idx,sub}) => { const raw = String(row[idx]||'').trim(); if (!raw || /^\d+$/.test(raw)) return; const key = [b.parity, day, pair, sub].join('|'); if (!slots[key]) slots[key] = { parity:b.parity, day, pair, subgroup:sub, type, subject:'', teacher:'', room:'' }; const parts = raw.split(/\r?\n| {2,}/).map(s=>s.trim()).filter(Boolean); parts.forEach(p => { const slot = slots[key]; if (!slot.room && ROOM_RX.test(p)) slot.room = ROOM_RX.exec(p)[1]; else if (!slot.teacher && TEACHER_RX.test(p)) slot.teacher = p; else if (!slot.subject) slot.subject = p; }); }); }); } // сортировка const raw = Object.values(slots).sort((a,b) => { const pa = PARITY_ORDER.indexOf(a.parity), pb = PARITY_ORDER.indexOf(b.parity); if (pa !== pb) return pa - pb; const dayOrder = { понедельник:1, вторник:2, среда:3, четверг:4, пятница:5 }; if (dayOrder[a.day] !== dayOrder[b.day]) return dayOrder[a.day] - dayOrder[b.day]; return a.pair - b.pair; }); // группировка по времени const byTime = {}; raw.forEach(slot => { const key = [slot.parity, slot.day, slot.pair].join('|'); if (!byTime[key]) byTime[key] = {}; byTime[key][slot.subgroup] = slot; }); // распределение по массивам const all = []; const sub1 = []; const sub2 = []; Object.values(byTime).forEach(group => { const s1 = group['1']; const s2 = group['2']; if (s1 && s2 && s1.subject === s2.subject) { // общая пара all.push({ ...s1, subgroup: 'all' }); sub1.push({ ...s1 }); sub2.push({ ...s2 }); } else { if (s1) sub1.push(s1); if (s2) sub2.push(s2); } }); // фильтр function finalize(arr) { const dayOrder = { понедельник:1, вторник:2, среда:3, четверг:4, пятница:5 }; return arr .filter(s => s.subject) .sort((a,b) => { const pa = PARITY_ORDER.indexOf(a.parity), pb = PARITY_ORDER.indexOf(b.parity); if (pa !== pb) return pa - pb; if (dayOrder[a.day] !== dayOrder[b.day]) { return dayOrder[a.day] - dayOrder[b.day]; } return a.pair - b.pair; }) .map((s,i) => ({ id: i + 1, ...s })); } return { all: finalize(all), sub1: finalize(sub1), sub2: finalize(sub2), }; } const fs = require('fs'); if (require.main === module) { fetchSchedule() .then(data => { fs.writeFileSync('bd.json', JSON.stringify(data, null, 2), 'utf-8'); console.log('Расписание сохранено'); }) .catch(err => { console.error('Ошибка', err.message); }); } module.exports = fetchSchedule;
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос