From bc09ada90eed2b13ad6a6d508efa2a806b389039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Wed, 19 Aug 2026 09:47:16 +0400 Subject: [PATCH] =?UTF-8?q?v0.0.39:=20=D0=BE=D0=BF=D1=82=D0=B8=D0=BC=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20apply=5Freplacements=20?= =?UTF-8?q?=E2=80=94=20=D0=BE=D0=B4=D0=BD=D0=BE=D0=BF=D1=80=D0=BE=D1=85?= =?UTF-8?q?=D0=BE=D0=B4=D0=BD=D0=B0=D1=8F=20=D0=B7=D0=B0=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20N=C3=97re.sub?= =?UTF-8?q?=20(=D1=83=D1=81=D0=BA=D0=BE=D1=80=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=B2=20=D1=80=D0=B0=D0=B7=D1=8B)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- History/2026-08-19-replacer-optimization.md | 45 +++++++++++++++++++++ drhider/replacer.py | 44 +++++++++++++++----- site/app.py | 2 +- 3 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 History/2026-08-19-replacer-optimization.md diff --git a/History/2026-08-19-replacer-optimization.md b/History/2026-08-19-replacer-optimization.md new file mode 100644 index 0000000..2f9f193 --- /dev/null +++ b/History/2026-08-19-replacer-optimization.md @@ -0,0 +1,45 @@ +# v0.0.39 — оптимизация apply_replacements (однопроходная замена) — 2026-08-19 + +**Дата:** 2026-08-19 +**Версия:** 0.0.38 → 0.0.39 +**Файл:** `drhider/replacer.py`, `site/app.py` (версия) + +--- + +## Суть + +Обфускация PDF 19 МБ шла 132.7с, из них ИИ (LLM) всего 7с — остальное (~125с) +тратил основной код. Замер выявил узкое место: `apply_replacements`. + +## Причина + +`apply_replacements` для **каждой** сущности из mapping делала **2 полных +прохода `re.sub` по всему тексту** (основной + фоллбэк `_md_tolerant_pattern`). +Сложность O(N_сущностей × размер_текста × 2) — квадратичная по числу сущностей. +При 300+ сущностей и тексте в несколько МБ — десятки секунд. + +Замер (0.9 МБ, 304 сущности): **17.3 с**. + +## Решение + +Однопроходная замена: +- Все ключи собираются в **один** regex-паттерн через альтернацию `(?:...|...)` + (по убыванию длины, с `re.escape`, границы `(?