Загрузка данных


import difflib
import os
import re
import openpyxl
from openpyxl.utils import get_column_letter

# ================= ФАЙЛЫ =================
FILE_MAIN = "result_perfect.xlsx"
FILE_NAGRUZKA = "Svodnaya_uchebnaya_nagruzka_12_09_2026_-_krasnym_izmenenia.xlsx"
FILE_PODRAZDEL = "Подразделения.xlsx"
FILE_OUTPUT = "result_ready.xlsx"
# =========================================


def resolve_file(filename, keyword=None):
  if os.path.exists(filename):
    return filename
  if os.path.exists(filename + ".xlsx"):
    return filename + ".xlsx"
  if filename.endswith(".xlsx.xlsx") and os.path.exists(filename[:-5]):
    return filename[:-5]
  if keyword:
    for f in os.listdir("."):
      if keyword.lower() in f.lower() and f.endswith(".xlsx") and not f.startswith("~$"):
        return f
  return filename


def clean_str(val):
  if val is None:
    return ""
  s = str(val).replace('"', "").replace("'", "").replace("«", "").replace("»", "")
  s = s.lower().replace("ё", "е")
  s = re.sub(r"\s+", " ", s)
  return s.strip()


# 1. Читаем Подразделения (Факультеты/Кафедры -> Шифр)
path_podr = resolve_file(FILE_PODRAZDEL, "подразделения")
print(f"1. Читаем Подразделения: {path_podr}")
wb_podr = openpyxl.load_workbook(path_podr, data_only=True)
kaf_to_shifr = {}

for sheet in wb_podr.worksheets:
  for row in sheet.iter_rows(values_only=True):
    if len(row) >= 3 and row[1] is not None and row[2] is not None:
      shifr = str(row[1]).strip()
      kaf_full = clean_str(row[2])
      if kaf_full and kaf_full != "факультеты/кафедры" and shifr.lower() != "шифр":
        kaf_to_shifr[kaf_full] = shifr

# 2. Читаем Сводную нагрузку (Дисциплина -> Кафедра)
path_nagr = resolve_file(FILE_NAGRUZKA, "svodnaya")
print(f"2. Читаем Сводную нагрузку: {path_nagr}")
wb_nagr = openpyxl.load_workbook(path_nagr, data_only=True)
subj_to_kaf = {}

for sheet in wb_nagr.worksheets:
  for row in sheet.iter_rows(values_only=True):
    if len(row) >= 3 and row[1] is not None and row[2] is not None:
      kaf_name = clean_str(row[1])
      subj_name = clean_str(row[2])
      if subj_name and subj_name != "дисциплина" and kaf_name != "кафедра":
        subj_to_kaf[subj_name] = kaf_name

# 3. Открываем основную таблицу
path_main = resolve_file(FILE_MAIN, "result")
print(f"3. Открываем основную таблицу: {path_main}")
wb_main = openpyxl.load_workbook(path_main)
ws_main = wb_main.active

# Выводим шапку таблицы, чтобы видеть все столбцы
headers = {}
for col_idx in range(1, ws_main.max_column + 1):
  h_val = clean_str(ws_main.cell(row=1, column=col_idx).value)
  headers[col_idx] = h_val
  print(f"   Столбец {get_column_letter(col_idx)} ({col_idx}): {ws_main.cell(row=1, column=col_idx).value}")

# Предмет всегда в столбце E (5)
col_subj = 5

# Ищем столбец ФИО и Кафедры ПО ВСЕЙ ТАБЛИЦЕ (только правее столбца E, чтобы никогда не трогать A-E!)
known_surnames = (
    "пулькова", "шалина", "шадрин", "филонов", "филиппович",
    "салихова", "бригида", "ван хааске", "гулина", "ермакова", "ефремов", "жихарева"
)

col_fio = None
col_kaf = None

# Сначала проверяем по всей таблице, в каком столбце реально лежат ФИО со скрина и "ЦПД"
fio_counts = {c: 0 for c in range(6, ws_main.max_column + 1)}
cpd_counts = {c: 0 for c in range(6, ws_main.max_column + 1)}

for row_idx in range(2, ws_main.max_row + 1):
  for c in range(6, ws_main.max_column + 1):
    val = clean_str(ws_main.cell(row=row_idx, column=c).value)
    if not val:
      continue
    if val == "цпд":
      cpd_counts[c] += 1
    if any(val.startswith(s) for s in known_surnames):
      fio_counts[c] += 1

if max(fio_counts.values(), default=0) > 0:
  col_fio = max(fio_counts, key=fio_counts.get)

if max(cpd_counts.values(), default=0) > 0:
  col_kaf = max(cpd_counts, key=cpd_counts.get)
elif col_fio:
  col_kaf = col_fio + 1

# Если вдруг по фамилиям не нашлось, ищем по заголовкам в строке 1 (среди столбцов >= 6)
if not col_fio:
  for c in range(6, ws_main.max_column + 1):
    if any(w in headers[c] for w in ("фио", "преподават")):
      col_fio = c
      break

if not col_kaf:
  for c in range(6, ws_main.max_column + 1):
    if "кафедр" in headers[c] and c != col_fio:
      col_kaf = c
      break

print(
    f"\n-> Выбраны столбцы для работы:\n"
    f"   Предмет: {get_column_letter(col_subj)} ({col_subj})\n"
    f"   ФИО препода: {get_column_letter(col_fio)} ({col_fio})\n"
    f"   Кафедра: {get_column_letter(col_kaf)} ({col_kaf})"
)

all_podr_names = list(kaf_to_shifr.keys())


def get_shifr_by_kaf_name(kaf_name):
  if not kaf_name:
    return None
  if kaf_name in kaf_to_shifr:
    return kaf_to_shifr[kaf_name]
  for k_podr, s_podr in kaf_to_shifr.items():
    if kaf_name in k_podr or k_podr in kaf_name:
      return s_podr
  close = difflib.get_close_matches(kaf_name, all_podr_names, n=1, cutoff=0.75)
  if close:
    return kaf_to_shifr[close[0]]
  return None


filled_kaf = 0
updated_fio = 0
fixed_col_a = 0

for row_idx in range(2, ws_main.max_row + 1):
  # Если в столбце A (Факультет) от прошлого запуска осталось "ФМ(ФМ)", возвращаем обратно "ФМ"
  cell_a = ws_main.cell(row=row_idx, column=1)
  if cell_a.value is not None:
    val_a = str(cell_a.value).strip()
    m = re.match(r"^(.+)\(\1\)$", val_a)
    if m:
      cell_a.value = m.group(1)
      fixed_col_a += 1

  cell_subj = ws_main.cell(row=row_idx, column=col_subj)
  cell_fio = ws_main.cell(row=row_idx, column=col_fio)
  cell_kaf = ws_main.cell(row=row_idx, column=col_kaf)

  subj_clean = clean_str(cell_subj.value)
  fio_raw = str(cell_fio.value).strip() if cell_fio.value is not None else ""
  kaf_raw = str(cell_kaf.value).strip() if cell_kaf.value is not None else ""

  # 1. Если ячейка кафедры пустая — ищем по предмету в нагрузке -> берем шифр из подразделений
  if not kaf_raw and subj_clean:
    kaf_full = subj_to_kaf.get(subj_clean)
    shifr = get_shifr_by_kaf_name(kaf_full)
    if shifr:
      kaf_raw = shifr
      cell_kaf.value = shifr
      filled_kaf += 1

  # 2. Если есть ФИО преподавателя и есть кафедра — приписываем (кафедра) без пробела
  if fio_raw and kaf_raw and fio_raw.lower() not in ("вакансия", "нет", "-"):
    fio_base = re.sub(r"\s*\([^)]*\)\s*$", "", fio_raw).strip()
    cell_fio.value = f"{fio_base}({kaf_raw})"
    updated_fio += 1

wb_main.save(FILE_OUTPUT)
print(f"\nГотово! Сохранено в файл: {FILE_OUTPUT}")
if fixed_col_a:
  print(f"— Очищено от дублей в столбце A (Факультет): {fixed_col_a}")
print(f"— Дозаполнено пустых кафедр: {filled_kaf}")
print(f"— Обновлено ФИО преподавателей со скобками: {updated_fio}")