Refactor code structure for improved readability and maintainability

This commit is contained in:
Dmitry
2026-04-12 21:49:19 +03:00
parent 645b2e9203
commit 96fa483703
11 changed files with 3104 additions and 14 deletions
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

+29
View File
@@ -0,0 +1,29 @@
Через базарную площадь идет полицейский надзиратель Очумелов в новой шинели и с узелком в руке. За ним шагает рыжий городовой с решетом, доверху наполненным конфискованным крыжовником. Кругом тишина... На площади ни души... Открытые двери лавок и кабаков глядят на свет божий уныло, как голодные пасти; около них нет даже нищих.
— Так ты кусаться, окаянная? — слышит вдруг Очумелов.— Ребята, не пущай ее! Нынче не велено кусаться! Держи! А... а!
Слышен собачий визг. Очумелов глядит в сторону и видит: из дровяного склада купца Пичугина, прыгая на трех ногах и оглядываясь, бежит собака. За ней гонится человек в ситцевой крахмальной рубахе и расстегнутой жилетке». Он бежит за ней и, подавшись туловищем вперед, падает на землю и хватает собаку за задние лапы. Слышен вторично собачий визг и крик: «Не пущай!» Из лавок высовываются сонные физиономии, и скоро около дровяного склада, словно из земли выросши, собирается толпа.
— Никак беспорядок, ваше благородие!..— говорит городовой.
Очумелов делает полуоборот налево и шагает к сборищу. Около самых ворот склада, видит он, стоит вышеписанный человек в расстегнутой жилетке и, подняв вверх правую руку, показывает толпе окровавленный палец. На полупьяном лице его как бы написано: «Ужо я сорву с тебя, шельма!» да и самый палец имеет вид знамения победы. В этом человеке Очумелов узнает золотых дел мастера Хрюкина. В центре толпы, растопырив передние ноги и дрожа всем телом, сидит на земле сам виновник скандала — белый борзой щенок с острой мордой и желтым пятном на спине. В слезящихся глазах его выражение тоски и ужаса.
— По какому это случаю тут? — спрашивает Очумелов, врезываясь в толпу.— Почему тут? Это ты зачем палец?.. Кто кричал?
— Иду я, ваше благородие, никого не трогаю...— начинает Хрюкин, кашляя в кулак.— Насчет дров с Митрий Митричем,— и вдруг эта подлая ни с того, ни с сего за палец... Вы меня извините, я человек, который работающий... Работа у меня мелкая. Пущай мне заплатят, потому — я этим пальцем, может, неделю не пошевельну... Этого, ваше благородие, и в законе нет, чтоб от твари терпеть... Ежели каждый будет кусаться, то лучше и не жить на свете...
— Гм!.. Хорошо...— говорит Очумелов строго, кашляя и шевеля бровями. — Хорошо... Чья собака? Я этого так не оставлю. Я покажу вам, как собак распускать! Пора обратить внимание на подобных господ, не желающих подчиняться постановлениям! Как оштрафуют его, мерзавца, так он узнает у меня, что значит собака и прочий бродячий скот! Я ему покажу Кузькину мать!.. Елдырин,— обращается надзиратель к городовому,— узнай, чья это собака, и составляй протокол! А собаку истребить надо. Немедля! Она наверное бешеная... Чья это собака, спрашиваю?
— Это, кажись, генерала Жигалова! — кричит кто-то из толпы.
— Генерала Жигалова? Гм!.. Сними-ка, Елдырин, с меня пальто... Ужас как жарко! Должно полагать, перед дождем... Одного только я не понимаю: как она могла тебя укусить? — обращается Очумелов к Хрюкину.— Нешто она достанет до пальца? Она маленькая, а ты ведь вон какой здоровила! Ты, должно быть, расковырял палец гвоздиком, а потом и пришла в твою голову идея, чтоб сорвать. Ты ведь... известный народ! Знаю вас, чертей!
— Он, ваше благородие, цыгаркой ей в харю для смеха, а она — не будь дура и тяпни... Вздорный человек, ваше благородие!
— Врешь кривой! Не видал, так, стало быть, зачем врать? Их благородие умный господин и понимают, ежели кто врет, а кто по совести, как перед богом... А ежели я вру, так пущай мировой рассудит. У него в законе сказано... Нынче все равны... У меня у самого брат в жандармах... ежели хотите знать...
— Не рассуждать!
— Нет, это не генеральская...— глубокомысленно замечает городовой.— У генерала таких нет. У него всё больше легавые...
— Ты это верно знаешь?
— Верно, ваше благородие...
— Я и сам знаю. У генерала собаки дорогие, породистые, а эта — чёрт знает что! Ни шерсти, ни вида... подлость одна только... И этакую собаку держать?!.. Где же у вас ум? Попадись этакая собака в Петербурге или Москве, то знаете, что было бы? Там не посмотрели бы в закон, а моментально — не дыши! Ты, Хрюкин, пострадал и дела этого так не оставляй... Нужно проучить! Пора...
— А может быть, и генеральская...— думает вслух городовой.— На морде у ней не написано... Намедни во дворе у него такую видел.
— Вестимо, генеральская! — говорит голос из толпы.
— Гм!.. Надень-ка, брат Елдырин, на меня пальто... Что-то ветром подуло... Знобит... Ты отведешь ее к генералу и спросишь там. Скажешь, что я нашел и прислал... И скажи, чтобы ее не выпускали на улицу... Она, может быть, дорогая, а ежели каждый свинья будет ей в нос сигаркой тыкать, то долго ли испортить. Собака — нежная тварь... А ты, болван, опусти руку! Нечего свой дурацкий палец выставлять! Сам виноват!..
— Повар генеральский идет, его спросим... Эй, Прохор! Поди-ка, милый, сюда! Погляди на собаку... Ваша?
— Выдумал! Этаких у нас отродясь не бывало!
— И спрашивать тут долго нечего,— говорит Очумелов.— Она бродячая! Нечего тут долго разговаривать... Ежели сказал, что бродячая, стало быть и бродячая... Истребить, вот и всё.
— Это не наша,— продолжает Прохор.— Это генералова брата, что намеднись приехал. Наш не охотник до борзых. Брат ихний охоч...
— Да разве братец ихний приехали? Владимир Иваныч? — спрашивает Очумелов, и всё лицо его заливается улыбкой умиления.— Ишь ты, господи! А я и не знал! Погостить приехали?
В гости...
— Ишь ты, господи... Соскучились по братце... А я ведь и не знал! Так это ихняя собачка? Очень рад... Возьми ее... Собачонка ничего себе... Шустрая такая... Цап этого за палец! Ха-ха-ха... Ну, чего дрожишь? Ррр... Рр... Сердится, шельма... цуцык этакий...
Прохор зовет собаку и идет с ней от дровяного склада... Толпа хохочет над Хрюкиным.
— Я еще доберусь до тебя! — грозит ему Очумелов и, запахиваясь в шинель, продолжает свой путь по базарной площади.
+1
View File
@@ -0,0 +1 @@
Рассказ Антона Чехова "Хамелеон" разворачивается в небольшом городе и начинается с того, что полицейский надзиратель Очумелов, персонаж с типичной для мелкого чиновника самоуверенностью и важностью, возвращается домой. Он внезапно становится свидетелем сборища народа, обсуждающего инцидент с собакой, которая укусила прохожего за ногу. Чехов описывает Очумелова как человека, одетого в форму, со знаками различия, что сразу подчеркивает его статус и самоощущение важности перед окружающими.Очумелов подходит к толпе, чтобы выяснить, что произошло. Он выслушивает разные мнения и начинает допрашивать свидетелей, демонстрируя при этом свою власть. Чехов через диалоги раскрывает характер Очумелова как типичного представителя власти, который готов мгновенно менять свою позицию в зависимости от того, как повернется ситуация в его пользу.Когда становится известно, что собака принадлежит золотарю, Очумелов решительно заявляет, что собаку следует уничтожить. Однако, услышав мнение, что собака может быть собственностью генерала Жигалова, его мнение кардинально меняется. Очумелов тут же начинает защищать собаку, утверждая, что она "не такая уж и злая", и пытается найти оправдания ее поведению, показывая свою податливость и стремление угодить авторитету.Чехов мастерски использует эти моменты, чтобы показать изменчивость мнений Очумелова, который словно хамелеон меняет свои убеждения в зависимости от обстоятельств. Эта черта характера подчеркивается и названием рассказа. Очумелов предстает перед читателем человеком, лишенным принципов и готовым на любые ухищрения ради сохранения своего положения.В конце рассказа, когда выясняется, что собака не принадлежит генералу, Очумелов снова меняет свою позицию, выражая недоумение и непонимание происходящего. Чехов заканчивает рассказ на этой ноте неопределенности, оставляя читателя размышлять о легкости, с которой мнения и убеждения могут меняться под воздействием внешних обстоятельств."Хамелеон" – это яркий пример чеховской сатиры на бюрократию и чиновничий мир, где власть и страх перед авторитетами могут полностью изменить человеческую природу, превращая личность в "хамелеона", постоянно меняющего свои цвета.
Binary file not shown.

After

Width:  |  Height:  |  Size: 439 KiB

+220
View File
@@ -0,0 +1,220 @@
from collections import Counter, defaultdict
from pathlib import Path
import math
import re
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import rcParams
rcParams["font.sans-serif"] = ["DejaVu Sans"]
rcParams["axes.unicode_minus"] = False
try:
import spacy
NLP = spacy.blank("ru")
except Exception:
NLP = None
def tok(text):
text = text.lower()
if NLP is not None:
return [t.text for t in NLP(text) if t.text.strip() and t.is_alpha]
return re.findall(r"\w+", text, flags=re.UNICODE)
def make_windows(words, k):
return [(i, " ".join(words[i : i + k]), set(words[i : i + k])) for i in range(max(0, len(words) - k + 1))]
def lev(a, b):
if a == b:
return 1.0
if not a or not b:
return 0.0
if len(a) < len(b):
a, b = b, a
prev = list(range(len(b) + 1))
for i, c1 in enumerate(a, 1):
cur = [i]
for j, c2 in enumerate(b, 1):
cur.append(min(cur[-1] + 1, prev[j] + 1, prev[j - 1] + (c1 != c2)))
prev = cur
return 1 - prev[-1] / max(len(a), len(b))
def jaro(a, b):
if a == b:
return 1.0
if not a or not b:
return 0.0
la, lb = len(a), len(b)
d = max(0, max(la, lb) // 2 - 1)
ma, mb, m = [0] * la, [0] * lb, 0
for i in range(la):
for j in range(max(0, i - d), min(i + d + 1, lb)):
if not mb[j] and a[i] == b[j]:
ma[i] = mb[j] = 1
m += 1
break
if m == 0:
return 0.0
t, j = 0, 0
for i in range(la):
if not ma[i]:
continue
while not mb[j]:
j += 1
t += a[i] != b[j]
j += 1
return (m / la + m / lb + (m - t / 2) / m) / 3
def winkler(a, b, p=0.1, bt=0.7):
dj = jaro(a, b)
if dj <= bt:
return dj
pref = 0
for x, y in zip(a[:4], b[:4]):
if x != y:
break
pref += 1
return dj + pref * p * (1 - dj)
def jaccard(a, b, n=2):
def ng(s):
if len(s) < n:
return {s} if s else set()
return {s[i : i + n] for i in range(len(s) - n + 1)}
x, y = ng(a), ng(b)
if not x and not y:
return 1.0
if not x or not y:
return 0.0
return len(x & y) / len(x | y)
def best_thr(vals, method):
if vals.size == 0:
return 1.0
grid = np.arange(0.65, 1.001, 0.01) if method in {"jaro", "jaro_winkler"} else (
np.arange(0.55, 1.001, 0.01) if method == "levenshtein" else np.arange(0.35, 1.001, 0.01)
)
best_t, best_q = float(grid[0]), -1.0
for t in grid:
s = vals[vals >= t]
if s.size == 0:
continue
q = 0.65 * float(np.mean(s)) + 0.35 * (s.size / vals.size)
if q > best_q:
best_t, best_q = float(t), q
return best_t
def score_pairs(w1, w2, sim, min_overlap):
idx = defaultdict(list)
for j, (_, _, terms) in enumerate(w2):
for term in terms:
idx[term].append(j)
out = []
for i, p1, t1 in w1:
c = Counter()
for term in t1:
for j in idx.get(term, []):
c[j] += 1
for j, ov in c.items():
if ov >= min_overlap:
out.append((p1, sim(p1, w2[j][1])))
return out
def analyze(words1, words2, ws=(5, 10, 20, 30), n=2, p=0.1, bt=0.7):
methods = {
"levenshtein": lev,
"jaro": jaro,
"jaro_winkler": lambda a, b: winkler(a, b, p, bt),
"jaccard": lambda a, b: jaccard(a, b, n),
}
stats = defaultdict(dict)
print("=" * 64)
print("АНАЛИЗ СХОЖЕСТИ ТЕКСТОВ")
print("=" * 64)
print(f"Текст 1: {len(words1)} слов")
print(f"Текст 2: {len(words2)} слов")
print(f"Токенизация: {'SpaCy' if NLP is not None else 'regex fallback'}")
for name, sim in methods.items():
print("\n" + "-" * 64)
print(name.upper())
print("-" * 64)
for k in ws:
w1, w2 = make_windows(words1, k), make_windows(words2, k)
scored = score_pairs(w1, w2, sim, max(1, math.ceil(k * 0.35)))
vals = np.array([x[1] for x in scored], dtype=float)
thr = best_thr(vals, name)
matched = [x for x in scored if x[1] >= thr]
total = sum(len(x[0]) for x in matched)
avg = float(np.mean([x[1] for x in matched])) if matched else 0.0
stats[name][k] = {
"threshold": thr,
"matches_count": len(matched),
"total_length": int(total),
"avg_similarity": avg,
}
print(f"окно={k:>2} | порог={thr:.2f} | совпадений={len(matched):>4} | длина={int(total):>5} | ср={avg:.3f}")
return stats
def plot(stats, ws, out):
methods = list(stats)
fig, ax = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle("Схожесть текстов", fontsize=14)
items = [
("matches_count", "Количество совпадений", "o", None),
("total_length", "Суммарная длина", "s", None),
("avg_similarity", "Средняя схожесть", "^", (0, 1)),
("threshold", "Оптимальные пороги", "D", (0, 1)),
]
for a, (key, title, marker, ylim) in zip(ax.flat, items):
for m in methods:
a.plot(ws, [stats[m][k][key] for k in ws], marker=marker, linewidth=2, label=m)
a.set_title(title)
a.set_xlabel("Размер окна (слов)")
if ylim:
a.set_ylim(*ylim)
a.grid(alpha=0.3)
a.legend()
plt.tight_layout()
img = out / "similarity_analysis.png"
plt.savefig(img, dpi=250, bbox_inches="tight")
print(f"\nСохранен график: {img}")
def main():
base = Path(__file__).resolve().parent
words1 = tok((base / "hameleon_short.txt").read_text(encoding="utf-8"))
words2 = tok((base / "hameleon.txt").read_text(encoding="utf-8"))
ws = [5, 10, 20, 30]
stats = analyze(words1, words2, ws=ws, n=2, p=0.1, bt=0.7)
print("\n" + "=" * 64)
print("ИТОГОВАЯ СВОДКА")
print("=" * 64)
for m in stats:
cnt = sum(stats[m][k]["matches_count"] for k in ws)
ln = sum(stats[m][k]["total_length"] for k in ws)
print(f"{m:>13}: совпадений={cnt:>4}, суммарная длина={ln:>5}")
plot(stats, ws, base)
print("\nАНАЛИЗ ЗАВЕРШЕН")
if __name__ == "__main__":
main()