# Copyright Stanislav Mironov import time import xlrd from coord import Coord, Merged from translations import ExcelSheetReader import re class StepTimeCounter: def __init__(self): self.time: float = -1.0 self.createtime = time.time() self.setnow() def setnow(self): self.time = time.time() def step(self, no_set_now=False): left = time.time() - self.time if not no_set_now: self.setnow() return left def from_create(self): left = time.time() - self.createtime return left EMPTY_CTYPES = [xlrd.XL_CELL_EMPTY, xlrd.XL_CELL_BLANK] def discards_list(trg, nones=True, emptystrings=True): if nones: remove_from_list(trg, [None]) if emptystrings: remove_from_list(trg, [""]) def has_no_bottom_border(reader: "ExcelSheetReader", coord): return reader.get_border_style(coord, 'bottom') == 0 and reader.get_border_style(coord.shift(down=1), 'top') == 0 def find_element_index(my_list, element): if element in my_list: return my_list.index(element) else: return -1 def next_element(arr, el): index = find_element_index(arr, el) return arr[index + 1] def remove_from_list(l: list, todel: list): for x in todel: if x in l: l.remove(x) return l def parse_all_dirt(reader: "ExcelSheetReader", min_pos: Coord, right, down, with_cells=False): 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)) cv = reader.cell(row, col) if cv is not None and not cv.is_empty(): RET.add(cv if with_cells else str(cv.value)) col += 1 row += 1 return RET # GEMINI GENERATED 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 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): """Убрать пробелы из текста""" if s is None: return "!!!Python None!!!" 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().startswith("ПОНЕД"): 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().startswith("ВОСКР"): return 7 return -1