Аудитории 223: видимый столбец важнее скрытого дубля

В листе «аудитории» два столбца с номером 223: видимый («комп.класс
Linux/Windows; интерактивная панель; маркер; 20 мест») и скрытый
(«компьютерный класс для МО и СТ; 24 места»). Парсер читал скрытый, потому что
скрытые столбцы пропускались только при поиске групп, а в описаниях аудиторий
нет — и он затирал видимый: у 223 не было ни панели, ни 20 мест.

Теперь в описаниях аудиторий скрытые столбцы обрабатываются после видимых и не
перекрывают их (аудитория, у которой есть только скрытый столбец, как 415/405/402,
по-прежнему разбирается). Заодно тип понимает «комп.класс Linux/Windows».

Проверено на таблице: 223 -> 20 мест, оснащение ПК + интерактивная панель + маркер,
тип «комп.класс linux/windows». Тесты: 170.
This commit is contained in:
2026-10-12 10:55:11 +03:00
parent a9d3f4d5cf
commit 172636f227
2 changed files with 56 additions and 6 deletions

View File

@@ -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

View File

@@ -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