py_stepik/mod_oop/3.5_08_morph.py

167 lines
7.3 KiB
Python
Raw Permalink Normal View History

2024-04-13 16:46:29 +00:00
"""
https://stepik.org/lesson/701990/step/8?unit=702091
Ваша задача написать программу поиска слова в строке. Задача усложняется тем, что слово должно определяться в разных его формах. Например, слово:
программирование
может иметь следующие формы:
программирование, программированию, программированием, программировании, программирования, программированиям, программированиями, программированиях
Для решения этой задачи необходимо объявить класс Morph (морфология), объекты которого создаются командой:
mw = Morph(word1, word2, ..., wordN)
где word1, word2, ..., wordN - возможные формы слова.
В классе Morph реализовать методы:
add_word(self, word) - добавление нового слова (если его нет в списке слов объекта класса Morph);
get_words(self) - получение кортежа форм слов.
Также с объектами класса Morph должны выполняться следующие операторы сравнения:
mw1 == "word" # True, если объект mv1 содержит слово "word" (без учета регистра)
mw1 != "word" # True, если объект mv1 не содержит слово "word" (без учета регистра)
И аналогичная пара сравнений:
"word" == mw1
"word" != mw1
После создания класса Morph, формируется список dict_words из объектов этого класса, для следующих слов с их словоформами:
- связь, связи, связью, связей, связям, связями, связях
- формула, формулы, формуле, формулу, формулой, формул, формулам, формулами, формулах
- вектор, вектора, вектору, вектором, векторе, векторы, векторов, векторам, векторами, векторах
- эффект, эффекта, эффекту, эффектом, эффекте, эффекты, эффектов, эффектам, эффектами, эффектах
- день, дня, дню, днем, дне, дни, дням, днями, днях
Затем, прочитайте строку из входного потока командой:
text = input()
Найдите все вхождения слов из списка dict_words (используя операторы сравнения) в строке text (без учета регистра, знаков пунктуаций и их словоформы). Выведите на экран полученное число.
"""
import sys
import subprocess
sys.stdin.reconfigure(encoding="utf-8")
def run_test(request, expected, num=0, count=0):
test_id = "" if num == 0 else f" #{num}" + (f"of {count}" if count else "")
p = subprocess.run(
[sys.executable, __file__],
input=f"{request}\n",
encoding="utf-8",
text=True,
capture_output=True,
)
if p.stderr:
print("StdErr:\n", p.stderr, file=sys.stderr)
p.check_returncode()
answer = (p.stderr + p.stdout).strip()
assert (
answer == expected
), f"""\nFailed test{test_id}. Wrong answer
This is a sample test from the problem statement!
Test input:
{request}
Correct output:
{expected}
Your code output:
{answer}
"""
def stdin_tests():
tests = [
("Мы будем устанавливать связь завтра днем.", "2"),
("Завтра после полудня мы установим контакт.", "0"),
("Напишите формулу L1-нормы вектора.", "2"),
("Ф:о@рм-у-л.а за формулой, д.е.н.ь за днем", "4"),
]
for i, test in enumerate(tests):
run_test(*test, i, len(tests))
if sys.argv[-1] == "test":
stdin_tests()
exit()
# ---------
from functools import total_ordering
@total_ordering
class Morph:
def __init__(self, *words):
self.words = set(map(str.lower, words))
# тесты просят сохранять порядок и дубликаты для get_words
# но только для исходных данных
# немножко возражаю, хочу set!
self.words_for_tests = list(map(str.lower, words))
def __repr__(self):
return f"{self.__class__.__name__}({', '.join(map(repr, self.words))})"
def add_word(self, word):
l0 = len(self)
self.words.add(word.lower())
if len(self) > l0:
self.words_for_tests.append(word.lower())
def get_words(self):
return tuple(self.words_for_tests)
def __len__(self):
return len(self.words)
def __radd__(self, other):
return self + other
def __add__(self, other):
if hasattr(other, "words"):
return self.__class__(*self.words, *other.words)
if isinstance(other, str):
return self.__class__(*self.words, *other.split())
return NotImplemented
def __contains__(self, other):
return self == other
def __eq__(self, other):
if hasattr(other, "words"):
return self.words == other.words
if isinstance(other, str):
return other.lower() in self.words
return NotImplemented
def __lt__(self, other):
if hasattr(other, "words"):
return self.words < other.words
if isinstance(other, str):
return other.lower() in self.words
return NotImplemented
def __gt__(self, other):
if hasattr(other, "words"):
return self.words > other.words
if isinstance(other, str):
return False
return NotImplemented
data = """\
- связь, связи, связью, связей, связям, связями, связях
- формула, формулы, формуле, формулу, формулой, формул, формулам, формулами, формулах
- вектор, вектора, вектору, вектором, векторе, векторы, векторов, векторам, векторами, векторах
- эффект, эффекта, эффекту, эффектом, эффекте, эффекты, эффектов, эффектам, эффектами, эффектах
- день, дня, дню, днем, дне, дни, дням, днями, днях\
"""
sanitizer = str.maketrans({k: "" for k in "?!,.:;()+-*^%$#@№/\\<>"})
dict_words = [*map(lambda x: Morph(*x.translate(sanitizer).split()), data.split("\n"))]
all_words = sum(dict_words, Morph())
text = input() # эту строчку не менять
words = [*map(lambda x: x.translate(sanitizer), text.split())]
print(sum(word in all_words for word in words))