Files
VSTU_Schedule_Parser/utils.py
2025-09-11 10:47:21 +03:00

170 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# gemini generated
import xlrd
from coord import Coord, Merged
EMPTY_CTYPES = [xlrd.XL_CELL_EMPTY, xlrd.XL_CELL_BLANK]
def border(sh, coord):
cell = sh.cell(coord.row, coord.col)
xf_style: "xlrd.formatting.XF" = sh.book.xf_list[cell.xf_index]
return xf_style.border
def border_right(sh, cell):
return border(sh, cell).right_line_style
def border_left(sh, cell):
return border(sh, cell).left_line_style
def border_bottom(sh, cell):
return border(sh, cell).bottom_line_style
def border_top(sh, cell):
return border(sh, cell).top_line_style
def parse_all_dirt(sh, min_pos, right, down):
RET = set()
row = min_pos.row
while row < min_pos.row + down:
col = min_pos.col
while col < min_pos.col + right:
#print(excel_coordinate(row, col))
value = str(sh.cell(row, col).value)
if value is not None and len(value) > 0:
RET.add(value)
col += 1
row += 1
return RET
import re
# GEMINI
def normalize_name(raw_name):
"""
Приводит разнородные записи ФИО к единому структурированному виду.
"""
# Шаг 1: Очистка
name = re.sub(r'\s+', ' ', raw_name).strip()
# Шаг 2: Извлечение звания
known_titles = ['проф.', 'доц.', 'акад.', 'к.т.н.', 'д.м.н.']
title = None
for t in known_titles:
if name.lower().startswith(t):
title = t
# Удаляем звание из строки, убираем лишние пробелы
name = name[len(t):].strip()
break
# Шаг 3 и 4: Разделение и идентификация
parts = name.split(' ')
last_name = None
initials = None
# Простой эвристический анализ
# Ищем инициалы (содержат точку или состоят из 1-2 заглавных букв)
initials_parts = []
name_parts = []
for part in parts:
if '.' in part or (1 <= len(part) <= 2 and part.isupper()):
initials_parts.append(part)
else:
# Считаем все остальное частью фамилии (для двойных фамилий)
name_parts.append(part)
if name_parts:
last_name = " ".join(name_parts)
if initials_parts:
initials = "".join(initials_parts) # Сливаем "А." и "Н." в "А.Н."
# Если фамилия не найдена (например, только инициалы),
# но есть части, считаем первую часть фамилией
if not last_name and name_parts:
last_name = name_parts[0]
return {
"last_name": last_name,
"initials": initials,
"title": title
}
def excel_coordinate(row, col):
"""
Преобразует координаты строки и столбца (начиная с 0) в эквивалент Excel (например, A7, CB34).
Args:
row: Индекс строки (начиная с 0).
col: Индекс столбца (начиная с 0).
Returns:
Строка, представляющая координату ячейки в стиле Excel.
~ Google Gemini, tested
"""
col_str = ''
while col >= 0:
col_str = chr(ord('A') + col % 26) + col_str # Преобразуем в буквы, начиная с A
col = col // 26 - 1 # Уменьшаем номер столбца и учитываем переход к следующему разряду (как в 26-ричной системе)
return col_str + str(row + 1) # Добавляем номер строки (Excel начинается с 1)
def get_merged(sh, rowx, colx):
"""Даём ей координаты ячейки таблицы а она выдаёт её границы если переданные координаты находятся 'внутри' объединённой ячейки"""
for crange in sh.merged_cells:
rlo, rhi, clo, chi = crange
chi -= 1
rhi -= 1
if rlo <= rowx <= rhi and chi >= colx >= clo:
return rlo, clo, rhi, chi
# если ячейка не часть объединённых то начала и концы у неё равны.
return rowx, colx, rowx, colx
def get_merged_coord(sh, coord):
merged = get_merged(sh, coord.row, coord.col)
return Merged(coord1=Coord(merged[0], merged[1]), coord2=Coord(merged[2], merged[3]))
def merged_humanize(crange):
"""Получить из 4 цифр границ AA:BB координаты как в Excel"""
row_low, col_low, row_high, col_high = crange # see order!
return excel_coordinate(row_low, col_low) + ":" + excel_coordinate(row_high, col_high)
def unspace(s: str):
"""Убрать пробелы из текста"""
return s.strip().replace(" ", "").replace("\t", "")
def find(sh, query = None):
for rx in range(sh.nrows):
i = 0
for x in sh.row(rx):
if x.value == query:
return rx, i
i += 1
return None
def weekday_to_num(st: str):
if st.upper().strip() == "ПОНЕДЕЛЬНИК":
return 1
if st.upper().strip() == "ВТОРНИК":
return 2
if st.upper().strip() == "СРЕДА":
return 3
if st.upper().strip() == "ЧЕТВЕРГ":
return 4
if st.upper().strip() == "ПЯТНИЦА":
return 5
if st.upper().strip() == "СУББОТА":
return 6
if st.upper().strip() == "ВОСКРЕСЕНЬЕ":
return 7
return -1