From 3f27404959e5ea3a8eb4e75f04963f6d6e659642 Mon Sep 17 00:00:00 2001 From: gitadmin Date: Sat, 15 Nov 2025 22:26:09 +0300 Subject: [PATCH] =?UTF-8?q?=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B8=20=D1=84?= =?UTF-8?q?=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=92=D0=9A=20=D1=82=D0=B5=D0=BA=D1=81?= =?UTF-8?q?=D1=82=D0=B0=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=83=D0=B1=D0=BB?= =?UTF-8?q?=D0=B8=D0=BA=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- formatter.py | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/formatter.py b/formatter.py index 0dc1d4d..d4b0ec6 100644 --- a/formatter.py +++ b/formatter.py @@ -1,7 +1,7 @@ import re def truncate_text(text, max_length): - """Обрезает текст до максимальной длины с учетом границ слов""" + """Обрезает текст до максимальной длины с учетом границ слов и HTML-тегов""" if text is None or not text: return "" @@ -12,6 +12,18 @@ def truncate_text(text, max_length): truncated = text[:max_length] last_space = truncated.rfind(' ') + # Проверяем, не обрезали ли мы HTML-тег + # Если после обрезки есть незакрытый тег 0: + # Проверяем, закрыт ли тег + after_tag = truncated[open_tag_pos:] + if '' not in after_tag: + # Тег не закрыт, обрезаем до начала тега + truncated = truncated[:open_tag_pos] + # Ищем последний пробел перед обрезанным тегом + last_space = truncated.rfind(' ') + if last_space > 0: return truncated[:last_space] + "..." return truncated[:max_length-3] + "..." @@ -30,22 +42,34 @@ def replace_vk_links(text): if not text: return text - # Сначала обрабатываем ссылки формата [url|текст] и преобразуем их в HTML-ссылки + # Сначала обрабатываем ВК-специфичные ссылки [club*|текст] и [id*|текст] + # Это нужно сделать до обработки обычных URL, чтобы не перехватывать их + vk_pattern = r'\[(?:club|id)\d+\|([^\]]+)\]' + text = re.sub(vk_pattern, r'\1', text) + + # Затем обрабатываем ссылки формата [url|текст] и преобразуем их в HTML-ссылки def replace_url_link(match): - url = match.group(1) - link_text = match.group(2) + url = match.group(1).strip() + link_text = match.group(2).strip() + + # Проверяем, что URL похож на ссылку (содержит http://, https://, или начинается с /) + # Это предотвращает обработку обычного текста в квадратных скобках как ссылки + if not (url.startswith('http://') or url.startswith('https://') or url.startswith('/') or url.startswith('#')): + # Если это не похоже на URL, возвращаем исходный текст без изменений + return match.group(0) + + # Экранируем кавычки в URL для безопасности + url = url.replace('"', '"') + # Экранируем HTML-сущности в тексте ссылки + link_text = link_text.replace('&', '&').replace('<', '<').replace('>', '>') return f'{link_text}' # Регулярное выражение для поиска ссылок формата [url|текст] - # Исключаем случаи, когда url начинается с club или id и цифр, за которыми сразу следует | (это обрабатывается отдельно) - url_pattern = r'\[(?!club\d+\||id\d+\|)([^\|]+)\|([^\]]+)\]' + # URL должен содержать хотя бы один символ, не быть пустым + url_pattern = r'\[([^\|\]]+)\|([^\]]+)\]' text = re.sub(url_pattern, replace_url_link, text) - # Регулярное выражение для поиска ссылок формата [типID|Текст] (ВК-специфичные) - vk_pattern = r'\[(?:club|id)\d+\|([^\]]+)\]' - - # Заменяем все вхождения на текст внутри ссылки - return re.sub(vk_pattern, r'\1', text) + return text def remove_html_tags(text): """Удаляет HTML-теги с учетом специальной обработки

и """