Аудитории: обозначения в нижнем регистре, аббревиатуры — заглавными
Тип, оснащение и пометки приводятся к одному виду: слова пишутся со строчной, а аббревиатуры («ПК», «МО», «СТ») остаются полностью заглавными; в подписях фильтров то же самое. В карточках теперь «комп.класс · 12 мест · ПК, маркер», «МО и СТ; без проектора». Тесты: 162.
This commit is contained in:
@@ -384,6 +384,18 @@ _ROOM_PART_SPLIT = re.compile(r"[;,]")
|
|||||||
_NEGATION_RE = re.compile(r"\bбез\b\s*(.*)", re.I)
|
_NEGATION_RE = re.compile(r"\bбез\b\s*(.*)", re.I)
|
||||||
|
|
||||||
|
|
||||||
|
_WORD_RE = re.compile(r"[A-Za-zА-ЯЁа-яё]+")
|
||||||
|
|
||||||
|
|
||||||
|
def lower_except_abbr(text: str) -> str:
|
||||||
|
"""Слова в нижний регистр; аббревиатуры («ПК», «МО», «СТ») остаёмся заглавными."""
|
||||||
|
def repl(match: re.Match) -> str:
|
||||||
|
word = match.group(0)
|
||||||
|
return word if len(word) >= 2 and word.isupper() else word.lower()
|
||||||
|
|
||||||
|
return _WORD_RE.sub(repl, text)
|
||||||
|
|
||||||
|
|
||||||
def room_capacity(text: str) -> int | None:
|
def room_capacity(text: str) -> int | None:
|
||||||
"""Вместимость: «N мест», «N раб.» (рабочие места в комп.классе)."""
|
"""Вместимость: «N мест», «N раб.» (рабочие места в комп.классе)."""
|
||||||
m = re.search(r"(\d+)\s*мест", text, re.I)
|
m = re.search(r"(\d+)\s*мест", text, re.I)
|
||||||
@@ -400,7 +412,7 @@ def room_type(text: str) -> str:
|
|||||||
for pattern in _ROOM_TYPE_PATTERNS:
|
for pattern in _ROOM_TYPE_PATTERNS:
|
||||||
m = pattern.search(text)
|
m = pattern.search(text)
|
||||||
if m:
|
if m:
|
||||||
return re.sub(r"\s{2,}", " ", m.group(0).strip(" .,"))
|
return lower_except_abbr(re.sub(r"\s{2,}", " ", m.group(0).strip(" .,")))
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@@ -440,7 +452,7 @@ def room_equipment(text: str) -> list[str]:
|
|||||||
if pattern.search(m.group(1)):
|
if pattern.search(m.group(1)):
|
||||||
negated.add(tag)
|
negated.add(tag)
|
||||||
return [
|
return [
|
||||||
tag
|
lower_except_abbr(tag)
|
||||||
for tag, pattern in _ROOM_EQUIPMENT
|
for tag, pattern in _ROOM_EQUIPMENT
|
||||||
if tag not in negated and pattern.search(text)
|
if tag not in negated and pattern.search(text)
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -436,6 +436,13 @@ function saveRoomsFilter() {
|
|||||||
localStorage.setItem(ROOMS_FILTER_KEY, JSON.stringify(roomsState.filter));
|
localStorage.setItem(ROOMS_FILTER_KEY, JSON.stringify(roomsState.filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Слова в нижний регистр, аббревиатуры («ПК», «МО») остаются заглавными. */
|
||||||
|
function lcWords(text) {
|
||||||
|
return String(text || "").replace(/[A-Za-zА-ЯЁа-яё]+/g, (word) =>
|
||||||
|
word.length >= 2 && word === word.toUpperCase() ? word : word.toLowerCase(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/** «Четверг» -> «четвергам» (для фразы «по четвергам и пятницам»). */
|
/** «Четверг» -> «четвергам» (для фразы «по четвергам и пятницам»). */
|
||||||
function weekdayPlural(day) {
|
function weekdayPlural(day) {
|
||||||
if (day.endsWith("ье")) return day.slice(0, -2) + "ьям"; // воскресенье
|
if (day.endsWith("ье")) return day.slice(0, -2) + "ьям"; // воскресенье
|
||||||
@@ -492,7 +499,7 @@ function roomInfoText(room) {
|
|||||||
if (tokens.every(isKnown)) return "";
|
if (tokens.every(isKnown)) return "";
|
||||||
const rest = [...tokens];
|
const rest = [...tokens];
|
||||||
while (rest.length && isKnown(rest[0])) rest.shift(); // убираем ведущие известные слова
|
while (rest.length && isKnown(rest[0])) rest.shift(); // убираем ведущие известные слова
|
||||||
return rest.join(" ");
|
return lcWords(rest.join(" "));
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join("; ");
|
.join("; ");
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ def test_rooms_info(sheets):
|
|||||||
|
|
||||||
assert info["ауд. 301"]["info"] == "интерактивная панель, 24 места"
|
assert info["ауд. 301"]["info"] == "интерактивная панель, 24 места"
|
||||||
assert info["ауд. 301"]["capacity"] == 24
|
assert info["ауд. 301"]["capacity"] == 24
|
||||||
assert info["ауд. 301"]["equipment"] == ["Интерактивная панель"]
|
assert info["ауд. 301"]["equipment"] == ["интерактивная панель"]
|
||||||
|
|
||||||
assert info["ауд. 220"]["info"] == "20 мест"
|
assert info["ауд. 220"]["info"] == "20 мест"
|
||||||
assert info["ауд. 220"]["type"] == ""
|
assert info["ауд. 220"]["type"] == ""
|
||||||
@@ -238,17 +238,17 @@ def test_room_attributes_from_descriptions():
|
|||||||
assert info["ауд. 201"]["type"] == "комп.класс"
|
assert info["ауд. 201"]["type"] == "комп.класс"
|
||||||
assert info["ауд. 201"]["capacity"] == 12
|
assert info["ауд. 201"]["capacity"] == 12
|
||||||
# «без проектора» — проектора нет, хотя слово в тексте есть
|
# «без проектора» — проектора нет, хотя слово в тексте есть
|
||||||
assert info["ауд. 201"]["equipment"] == ["ПК", "Маркер"]
|
assert info["ауд. 201"]["equipment"] == ["ПК", "маркер"]
|
||||||
assert info["ауд. 201"]["available_days"] is None
|
assert info["ауд. 201"]["available_days"] is None
|
||||||
|
|
||||||
assert info["ауд. 203"]["type"] == "аудитория для практических"
|
assert info["ауд. 203"]["type"] == "аудитория для практических"
|
||||||
assert info["ауд. 203"]["equipment"] == ["Меловая доска"]
|
assert info["ауд. 203"]["equipment"] == ["меловая доска"]
|
||||||
assert info["ауд. 203"]["capacity"] == 44
|
assert info["ауд. 203"]["capacity"] == 44
|
||||||
|
|
||||||
assert info["ауд. 210"]["equipment"] == ["ПК", "Проектор", "Маркер"]
|
assert info["ауд. 210"]["equipment"] == ["ПК", "проектор", "маркер"]
|
||||||
|
|
||||||
assert info["ауд. 305"]["type"] == "кабинет английского"
|
assert info["ауд. 305"]["type"] == "кабинет английского"
|
||||||
assert info["ауд. 305"]["equipment"] == ["Телевизор", "Маркер"]
|
assert info["ауд. 305"]["equipment"] == ["телевизор", "маркер"]
|
||||||
|
|
||||||
assert info["ауд. 402"]["available_days"] == ["четверг", "пятница"]
|
assert info["ауд. 402"]["available_days"] == ["четверг", "пятница"]
|
||||||
assert info["ауд. 402"]["capacity"] is None
|
assert info["ауд. 402"]["capacity"] is None
|
||||||
@@ -265,7 +265,7 @@ def test_room_payload_shape():
|
|||||||
"type": "лекционная",
|
"type": "лекционная",
|
||||||
"type_group": "лекционная",
|
"type_group": "лекционная",
|
||||||
"capacity": 96,
|
"capacity": 96,
|
||||||
"equipment": ["Проектор"],
|
"equipment": ["проектор"],
|
||||||
"available_days": None,
|
"available_days": None,
|
||||||
})
|
})
|
||||||
assert payload == {
|
assert payload == {
|
||||||
@@ -274,7 +274,7 @@ def test_room_payload_shape():
|
|||||||
"type": "лекционная",
|
"type": "лекционная",
|
||||||
"type_group": "лекционная",
|
"type_group": "лекционная",
|
||||||
"capacity": 96,
|
"capacity": 96,
|
||||||
"equipment": ["Проектор"],
|
"equipment": ["проектор"],
|
||||||
"available_days": None,
|
"available_days": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,3 +291,11 @@ def test_room_type_group_merges_similar():
|
|||||||
assert parsing.room_type_group("лекционно-практическая") == "лекционно-практическая"
|
assert parsing.room_type_group("лекционно-практическая") == "лекционно-практическая"
|
||||||
assert parsing.room_type_group("аудитория для практических") == "аудитория для практических"
|
assert parsing.room_type_group("аудитория для практических") == "аудитория для практических"
|
||||||
assert parsing.room_type_group("") == ""
|
assert parsing.room_type_group("") == ""
|
||||||
|
|
||||||
|
|
||||||
|
def test_lowercase_except_abbreviations():
|
||||||
|
"""Обозначения — в нижнем регистре, аббревиатуры остаются заглавными."""
|
||||||
|
assert parsing.room_type("комп.класс Linux; 10 мест") == "комп.класс linux"
|
||||||
|
assert parsing.room_type("Кабинет Английского") == "кабинет английского"
|
||||||
|
assert parsing.room_equipment("ПК, Проектор, интернет МО") == ["ПК", "проектор"]
|
||||||
|
assert parsing.lower_except_abbr("МО и СТ; без проектора") == "МО и СТ; без проектора"
|
||||||
|
|||||||
Reference in New Issue
Block a user