Как правильно обрабатывать объединённые ячейки?

Ссылка скопирована
0 ответов

По вводным: решил сделать бота в 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;
Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно