diff --git a/src/backend/schedule/parsing.py b/src/backend/schedule/parsing.py index f9dd508..ef68a22 100644 --- a/src/backend/schedule/parsing.py +++ b/src/backend/schedule/parsing.py @@ -351,8 +351,11 @@ def build_room_schedule(rooms: dict, label: str, day_times: dict | None = None) # Тип берём фразой как в таблице (порядок — от специфичных к общим). _ROOM_TYPE_PATTERNS = [ - re.compile(r"комп\.?\s*класс(?:\s+(?:Linux|Windows|OS))?", re.I), - re.compile(r"компьютерн\w*\s+класс(?:\s+(?:Linux|Windows|OS))?", re.I), + re.compile(r"комп\.?\s*класс(?:\s+(?:Linux|Windows|OS)(?:\s*[/,]\s*(?:Linux|Windows|OS))*)?", re.I), + re.compile( + r"компьютерн\w*\s+класс(?:\s+(?:Linux|Windows|OS)(?:\s*[/,]\s*(?:Linux|Windows|OS))*)?", + re.I, + ), re.compile(r"кабинет\s+англ\w*", re.I), re.compile(r"лекционно-практическая", re.I), re.compile(r"лекционная", re.I), @@ -475,15 +478,17 @@ def parse_rooms_info(sheets: dict[str, Worksheet]) -> dict: return {} header, desc = sheet.rows[0], sheet.rows[1] info: dict = {} - for col in range(_FIRST_GROUP_COL, max(len(header), len(desc))): + + def add(col: int) -> None: m = re.search(r"(\d+)", str(header[col])) if not m: - continue - number = m.group(1) + return + label = f"ауд. {m.group(1)}" + if label in info: + return # видимый столбец важнее скрытого дубля с тем же номером text = _strip_marks( " ".join(ln.strip() for ln in str(desc[col]).split("\n") if ln.strip()) ) - label = f"ауд. {number}" room_kind = room_type(text) info[label] = { "room": label, @@ -494,6 +499,14 @@ def parse_rooms_info(sheets: dict[str, Worksheet]) -> dict: "equipment": room_equipment(text), "available_days": room_weekdays(text), } + + columns = range(_FIRST_GROUP_COL, max(len(header), len(desc))) + for col in columns: # сначала видимые + if col not in sheet.hidden_cols: + add(col) + for col in columns: # потом скрытые: аудитория без видимого столбца тоже нужна + if col in sheet.hidden_cols: + add(col) return info diff --git a/tests/test_parsing.py b/tests/test_parsing.py index cae60ae..9ceca59 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -299,3 +299,40 @@ def test_lowercase_except_abbreviations(): assert parsing.room_type("Кабинет Английского") == "кабинет английского" assert parsing.room_equipment("ПК, Проектор, интернет МО") == ["ПК", "проектор"] assert parsing.lower_except_abbr("МО и СТ; без проектора") == "МО и СТ; без проектора" + + +def test_room_visible_column_wins_over_hidden_duplicate(): + """У 223 в таблице два столбца: видимый (с панелью) и скрытый (без). Берём видимый.""" + from xlsx_builder import SheetSpec + + spec = SheetSpec( + rows=[ + [None] * 6 + ["223", "223"], + [None] * 6 + [ + "комп.класс Linux/Windows; интерактивная панель; маркер; 20 мест", + "компьютерный класс для МО и СТ; 24 места", + ], + ], + hidden_cols=[(7, 7)], + ) + info = parsing.parse_rooms_info(make_sheets({parsing.ROOMS_SHEET: spec})) + room = info["ауд. 223"] + assert room["capacity"] == 20 + assert "интерактивная панель" in room["equipment"] + assert room["type"] == "комп.класс linux/windows" + + +def test_room_only_in_hidden_column_still_parsed(): + """Аудитория, у которой есть только скрытый столбец, не пропадает.""" + from xlsx_builder import SheetSpec + + spec = SheetSpec( + rows=[ + [None] * 6 + ["402", "410"], + [None] * 6 + ["402 четверг пятница", "проектор; 30 мест"], + ], + hidden_cols=[(6, 7)], + ) + info = parsing.parse_rooms_info(make_sheets({parsing.ROOMS_SHEET: spec})) + assert info["ауд. 402"]["available_days"] == ["четверг", "пятница"] + assert info["ауд. 410"]["capacity"] == 30