import re def truncate_text(text, max_length): """Обрезает текст до максимальной длины с учетом границ слов и HTML-тегов""" if text is None or not text: return "" if len(text) <= max_length: return text # Ищем последний пробел перед максимальной длиной 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] + "..." def safe_text(text): """Обеспечивает безопасное использование текста (заменяет None на пустую строку)""" return text if text is not None else "" def replace_vk_links(text): """ Заменяет ссылки на сообщества ВК в форматах: [club123|Название сообщества] -> Название сообщества [id456|Имя пользователя] -> Имя пользователя [текст](url) -> текст (для Telegram) [url|текст] -> текст (для Telegram) """ if not text: return text # Сначала обрабатываем ВК-специфичные ссылки [club*|текст] и [id*|текст] # Это нужно сделать до обработки обычных URL, чтобы не перехватывать их vk_pattern = r'\[(?:club|id)\d+\|([^\]]+)\]' text = re.sub(vk_pattern, r'\1', text) # Затем обрабатываем Markdown-ссылки [текст](url) и преобразуем их в HTML-ссылки def replace_markdown_link(match): link_text = match.group(1).strip() url = 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}' # Регулярное выражение для поиска Markdown-ссылок формата [текст](url) markdown_pattern = r'\[([^\]]+)\]\(([^\)]+)\)' text = re.sub(markdown_pattern, replace_markdown_link, text) # Затем обрабатываем ссылки формата [url|текст] и преобразуем их в HTML-ссылки def replace_url_link(match): 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 должен содержать хотя бы один символ, не быть пустым url_pattern = r'\[([^\|\]]+)\|([^\]]+)\]' text = re.sub(url_pattern, replace_url_link, text) return text def remove_html_tags(text): """Удаляет HTML-теги с учетом специальной обработки
и """
if not text:
return text
# Заменяем и