py_stepik/mod_oop/3.5_08_morph.py
2024-04-13 19:46:29 +03:00

167 lines
7.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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))