Python textwrap: как переверстать абзацы расшифровки без склейки говорящих
Новая ширина строк TXT через textwrap.fill с сохранением границ абзацев. Когда метод подходит, как подготовить разделители и проверить реплики после перевёрстки.
Сначала проверьте структуру исходника
После переноса из редактора TXT иногда содержит короткие строки фиксированной ширины: одна реплика разбита на несколько физических строк. Для дальнейшего чтения или вставки в другой документ полезно переверстать её под выбранную ширину.
Способ ниже подходит только при ясном соглашении: пустая строка отделяет самостоятельный абзац, обычные переносы внутри него — жёсткая разбивка одной реплики. Если каждый говорящий начинается с новой строки без пустого разделителя, такой код склеит их. Сначала подготовьте границы вручную или выберите другой разбор.
Работайте с отдельной paragraphs.txt, сохранив исходник. Полученную через расшифровку аудио сначала проверьте по говорящим и таймкодам. Автоматическая ширина строк не распознаёт смену участника.
Разделите абзацы до вызова fill
textwrap.fill обрабатывает один абзац и возвращает строку с новыми переносами. Если передать ему весь файл, границы самостоятельных реплик могут исчезнуть. Поэтому учебный код сначала разбивает текст по пустым строкам, а потом обрабатывает каждый блок отдельно.
width=80 задаёт желаемую ширину в символах, а не в пикселях браузера. break_long_words=False и break_on_hyphens=False оставляют длинные слова и дефисные формы целиком. Из-за этого отдельная строка может оказаться длиннее 80 символов — это ожидаемое следствие выбранного правила.
Обычные CRLF и CR в рабочей строке сначала заменяются на LF. Если Вам нужно только унифицировать окончания, используйте отдельную нормализацию переносов. Перевёрстка ниже дополнительно меняет пробелы и внутреннюю разбивку.
Создайте перевёрстанную копию
Сохраните код как rewrap.py рядом с paragraphs.txt и запустите python rewrap.py или python3 rewrap.py. Начните с двух учебных реплик, отделённых пустой строкой, и небольшого width, чтобы изменения были заметны.
from pathlib import Path
from textwrap import fill
import re
text = Path("paragraphs.txt").read_text(encoding="utf-8-sig")
text = text.replace("\r\n", "\n").replace("\r", "\n")
blocks = re.split(r"\n[ \t]*\n+", text.strip())
result = []
for block in blocks:
paragraph = " ".join(line.strip() for line in block.splitlines())
result.append(fill(paragraph, width=80,
break_long_words=False, break_on_hyphens=False))
with Path("paragraphs-wrapped.txt").open(
"x", encoding="utf-8", newline="\n"
) as saved:
saved.write("\n\n".join(result) + "\n")
print("Абзацев обработано:", len(result))
В этом примере несколько пустых разделителей сводятся к одному, крайние пробелы строк убираются, а переносы внутри блока становятся пробелами перед новой разбивкой. Поэтому его нельзя называть побайтовым сохранением или применять к форматам с содержательными отступами.
Не используйте такой разбор для SRT, таблицы CSV, кода или списка с зависимыми строками. У этих форматов переносы участвуют в структуре, и простое соединение способно её нарушить.
Проверьте слова и переходы между участниками
Сравните число абзацев и начало каждого блока. Проверьте, что подпись второго говорящего не появилась внутри первого ответа. Отдельно просмотрите длинный термин, дефисную форму, таймкод и последнюю реплику.
Для сравнения старой и новой копии полезен HTML-отчёт difflib. Переносы создадут заметные различия, поэтому читайте спорные фрагменты целиком и проверяйте последовательность слов.
Если в конце физической строки стоит дефис переноса из печатной вёрстки, скрипт не угадает, нужно ли его удалить. «транс-» и «крибация» останутся отдельными частями с пробелом. Такие случаи требуют отдельной проверки, чтобы не повредить настоящий дефис в слове.
Учебный пример: два абзаца остаются двумя
Вымышленный TXT содержит две реплики, между которыми заранее поставлена пустая строка.
| До | Обработка | После |
|---|---|---|
| А: Обсудим срок поставки. | Перенос внутри блока → пробел | А: Обсудим срок поставки. |
| Пустая строка | Граница блока | Пустая строка |
| Б: Подготовлю новый план. | Отдельный вызов fill | Б: Подготовлю новый план. |
Если в исходнике нет надёжных разделителей, не используйте чистый результат как доказательство сохранённой структуры: сначала исправьте соглашение о входе.
Проверка перевёрстки абзацев
Исходная копия: [имя] Граница абзаца: [правило] Все говорящие разделены: [проверено] Ширина: [число символов] Длинные слова: [не разрываются] Абзацев до и после: [числа] Переходы участников: [контрольные места] Дефисы переноса: [проверены] Результат: [имя копии]
Частые вопросы
Можно передать весь TXT в fill?
Если в нём несколько самостоятельных реплик, сначала разделите их на подтверждённые блоки.
Строка длиннее width — обязательно ошибка?
Нет. При запрете разрыва длинных слов отдельное слово может превышать выбранную ширину.
Код сохраняет все пробелы и пустые строки?
Нет. Он меняет пробельное оформление по описанным правилам.
Подходит ли способ для SRT или CSV?
Нет. Для этих структурированных форматов нужен отдельный разбор.