2.6 KiB
2.6 KiB
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, границы(?<!\w)...(?!\w)для alnum-сущностей). - Один
re.subс callback (lookup в mapping), O(text). - Фоллбэк
_md_tolerant_patternприменяется только к ключам, не найденным основной заменой (отслеживание черезmatched_keys), а не ко всем.
Результат замера
- 300 сущностей реально в тексте (1.3 МБ): 1.17 с (было бы десятки сек).
- Реалистичный сценарий (10 сущностей): 0.29 с.
- Согласованность токенов и mapping.csv сохранены (проверено через
obfuscate).
Проверка
test_replacer10/10,test_builder20/20,test_scanner20/20,test_zip28/28.- Пайплайн
obfuscate: «ООО Ромашка»→«Вектор_0001» в двух файлах согласовано, mapping.csv корректен.
Примечание
scan_regex(0.4с) и upload (сеть ~1.7 МБ/с) — не узкие места, не трогали.pdf_to_markdown(pdfplumber) локально не замерен (нет библиотеки); остаётся потенциальным вторым узким местом для будущей оптимизации (pypdf/pdfminer).