Переносы строк в TXT-расшифровке: как проверить CRLF и сохранить LF через Python
Диагностика окончаний строк CRLF, LF и CR, отдельная копия UTF-8 и контроль текста после записи. Почему нормализация переносов не должна склеивать реплики.
Убедитесь, что проблема именно в окончаниях строк
TXT может нормально открываться в одном инструменте и выглядеть необычно в другом, если по-разному обрабатываются окончания строк. CRLF — пара символов возврата каретки и перевода строки, LF — один перевод строки, CR — отдельный возврат каретки.
Сначала проверьте контрольный файл в простом редакторе. Если буквы нечитаемы, причина может быть в кодировке, а не в переносах. Если длинная реплика визуально переносится по ширине окна, это тоже не обязательно означает реальные символы конца строки.
Работайте с копией проверенной расшифровки. Для получения исходного текста доступна расшифровка аудио. Изменение представления файла не должно незаметно менять порядок говорящих или объединять ответы.
Посчитайте CRLF без двойного учёта
Для диагностики скрипт сначала считает пары CRLF в байтах, затем удаляет эти пары из временной байтовой строки и считает оставшиеся CR и LF. Иначе каждый CRLF одновременно оказался бы ещё одним CR и LF в отчёте.
Эти числа показывают обычные окончания строк в файле. Они не являются числом реплик: одна реплика может занимать несколько строк, а пустая строка тоже имеет окончание. Другие специальные разделители Unicode этот байтовый отчёт не перечисляет.
На учебном файле «А» + CRLF + «Б» + LF + «В» + CR должно получиться по одному окончанию каждого вида. Это помогает понять отчёт до применения к большой расшифровке.
Сохраните отдельную копию с LF
Сохраните код как normalize_newlines.py рядом с transcript.txt и выполните python normalize_newlines.py или python3 normalize_newlines.py. У входа предполагается UTF-8 с необязательной начальной меткой BOM. Код не угадывает другие кодировки.
from pathlib import Path
source = Path("transcript.txt")
output = Path("transcript-lf.txt")
raw = source.read_bytes()
without_pairs = raw.replace(b"\r\n", b"")
print("CRLF:", raw.count(b"\r\n"))
print("Отдельные CR:", without_pairs.count(b"\r"))
print("Отдельные LF:", without_pairs.count(b"\n"))
with source.open(encoding="utf-8-sig", newline=None) as opened:
text = opened.read()
with output.open("x", encoding="utf-8", newline="\n") as saved:
saved.write(text)
with output.open(encoding="utf-8", newline="") as checked:
if checked.read() != text:
raise ValueError("Текст после записи не совпал")
print("Сохранена отдельная копия:", output)
newline=None у чтения преобразует CRLF и CR в . newline=" " у записи сохраняет LF. Имя transcript-lf.txt отличается от исходника, а режим "x" не перезаписывает существующую копию.
Символьный текст, пустые строки и финальный перенос не удаляются через strip. Метка BOM при чтении utf-8-sig убирается, а выход записывается как UTF-8 без BOM. Поэтому это не побайтовая копия исходника и не должна называться неизменённым файлом.
Сверьте границы реплик и дальнейший импорт
После записи код повторно читает результат и сравнивает с нормализованным текстом в памяти. Затем откройте копию в целевом инструменте и проверьте начало, середину, конец, пустые строки и переход между говорящими.
Не применяйте замену всех переносов на пробел. Она способна склеить отдельные реплики. Если цель — убрать жёсткую разбивку внутри абзацев, это отдельная задача с другими правилами: сначала определите, где проходят границы смысловых блоков.
Изменения между двумя TXT можно увидеть через HTML-отчёт о правках. Для удобного просмотра одной копии подойдёт HTML-представление текста. Эти инструменты помогают проверить результат, но не заменяют прослушивание спорных реплик.
Учебный пример: три окончания строки
Вымышленный текст содержит по одному CRLF, LF и CR. После нормализации обычные окончания представлены одинаково.
| В исходнике | В отчёте | В LF-копии |
|---|---|---|
| А + CRLF | CRLF: 1 | А + LF |
| Б + LF | Отдельные LF: 1 | Б + LF |
| В + CR | Отдельные CR: 1 | В + LF |
Проверьте также пример с пустой строкой между ответами. Пустой разделитель должен сохраниться и после нормализации.
Проверка окончаний TXT
Исходный файл: [имя] Кодировка: [подтверждённая] CRLF: [число] Отдельные CR: [число] Отдельные LF: [число] Копия с LF: [имя] Пустые строки: [сохранены] Границы говорящих: [проверены] Целевой инструмент: [название] Контроль импорта: [результат]
Частые вопросы
CRLF считается двумя строками?
Это одно обычное окончание строки из двух символов. Отдельный подсчёт пар избегает двойного учёта.
Нужно удалять все пустые строки?
Нет. Они могут отделять смысловые блоки. Их удаление требует отдельного решения.
Скрипт исправит нечитаемые буквы?
Нет. Вход предполагает UTF-8. Проблему другой кодировки нужно разобрать отдельно.
Новая копия идентична исходнику в байтах?
Нет. Окончания строк меняются, а необязательная метка BOM не переносится.