#!/usr/bin/env python3 """Утилиты для очистки текста (ANSI-коды, нормализация).""" import re def clean_ansi_codes(text: str) -> str: """ Очистка ANSI-кодов и мусора из вывода терминала. Обрабатывает: - ANSI escape-последовательности \x1b[...m - «Битые» ANSI-коды без escape-символа (например [33m, [0m) - Символы замены Unicode () - Кириллические имитации ANSI-кодов (например [0м) """ # Удаляем ANSI escape-последовательности text = re.sub(r'\x1b\[[0-9;?]*[a-zA-Z]', '', text) # Удаляем «битые» ANSI-коды: [33m, [0m, [1m и т.д. (латиница и кириллица) text = re.sub(r'\[\d+[мm]', '', text) # Удаляем символы замены Unicode text = text.replace('\ufffd', '') return text def normalize_output(text: str) -> str: """ Нормализовать вывод: обработать \r и убрать пустые строки. \r используется для перезаписи строки (прогресс-баров). """ # Заменяем \r\n на \n text = text.replace('\r\n', '\n') # Обрабатываем \r (возврат каретки) — строки с \r перезаписывают друг друга lines = [] for line in text.split('\n'): if '\r' in line: # Разбиваем по \r и берём последнюю часть (финальное состояние) parts = line.split('\r') line = parts[-1] lines.append(line) text = '\n'.join(lines) # Разбиваем на строки, убираем пустые и trailing пробелы lines = text.split('\n') lines = [line.rstrip() for line in lines if line.strip()] # Очищаем прогресс-бары вида "Текст… 0%Текст… 50%Текст… 100%" # И дублирующийся текст cleaned_lines = [] for line in lines: # Ищем повторяющийся паттерн "текст… цифры%" progress_pattern = re.compile(r'((?:.+?\.{3})\d+%)+') match = progress_pattern.search(line) if match: # Берём последнее вхождение items = re.findall(r'(.+?\.{3})(\d+)%', match.group(0)) if items: last_text, last_percent = items[-1] line = line[:match.start()] + f'{last_text}{last_percent}%' + line[match.end():] # СНАЧАЛА удаляем остатки ANSI-кодов из строки # line = re.sub(r'.', '', line) # ← ЭТО УДАЛЯЛО ВСЁ! Закомментировал line = clean_ansi_codes(line) # ← Используем правильную функцию # Удаляем дублирующийся текст вида "0% [текст] 0% [текст]" dup_pattern = re.compile(r'(\d+%\s*\[.+?\])(?:\s*\d+%\s*\[.+?\])+') match = dup_pattern.search(line) if match: # Оставляем только первое вхождение line = line[:match.start()] + match.group(1) + line[match.end():] # Удаляем ведущие пробелы (артефакты терминала) line = line.lstrip() if line: cleaned_lines.append(line) return '\n'.join(cleaned_lines)