82 lines
3.4 KiB
Python
82 lines
3.4 KiB
Python
#!/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) # + любой символ
|
||
|
||
# Удаляем дублирующийся текст вида "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)
|