Перенос строки — это управляющий символ или их последовательность, которые отмечают конец одной строки текста и начало следующей. В файле это не «пустота» и не нажатие Enter само по себе, а конкретные байты: чаще всего это \n (LF), реже \r (CR) или их пара \r\n (CRLF). Ниже разберем, чем эти символы отличаются, почему в Windows, Linux и macOS они разные, как перенести строку в HTML тегом <br> и какие ошибки возникают при работе с текстовыми данными.
Содержание
Что такое символ новой строки
Когда вы нажимаете Enter в редакторе, программа вставляет в текст невидимый управляющий символ. Именно он и есть перенос строки. В большинстве языков программирования такие символы записывают через обратный слэш — это называется escape-последовательность:
\n— LF (Line Feed, «перевод строки», код 10, или 0x0A). Изначально команда сдвинуть бумагу в печатной машинке на строку вниз.\r— CR (Carriage Return, «возврат каретки», код 13, или 0x0D). Изначально команда вернуть каретку к левому краю.
Разделение на два символа осталось с эпохи телетайпов, где начать новую строку означало и опустить валик (LF), и вернуть каретку в начало (CR). Компьютеры унаследовали эти коды, но распорядились ими по-разному — отсюда и путаница между ОС.
Различия между Windows, Unix и старым Mac
Разные операционные системы исторически выбрали разные символы для обозначения конца строки. Это главный источник проблем при переносе файлов между системами.
| Обозначение | Escape | Код (dec / hex) | Где используется по умолчанию |
|---|---|---|---|
| LF | \n |
10 / 0x0A | Unix, Linux, macOS (с 2001 года) |
| CR | \r |
13 / 0x0D | Классический Mac OS (до версии 9, до 2001 года) |
| CRLF | \r\n |
13 10 / 0x0D 0x0A | Windows, MS-DOS; сетевые протоколы HTTP, SMTP |
Ключевые моменты, которые стоит запомнить:
- Windows использует пару
\r\n. Именно поэтому текстовый файл из Windows, открытый простым инструментом в Linux, иногда показывает в конце строк лишний символ^M— это и есть «висящий»\r. - Классический Mac OS (System 9 и раньше) применял одиночный
\r; сегодня это история, но такие переносы встречаются в старых данных. - В сетевых протоколах (HTTP, SMTP, FTP) разделителем строк по стандарту служит CRLF, независимо от ОС сервера.
Перенос строки в коде: примеры
Разберем поведение символов на коде. Примеры на Python 3 (актуальная ветка на 2026 год — Python 3.13), их можно запустить как есть.
Печать строки с переносом внутри:
text = "первая строка\nвторая строка"
print(text)
# первая строка
# вторая строка
print(repr(text))
# 'первая строка\nвторая строка'
Функция print интерпретирует \n как реальный перенос, а repr показывает строку «как она записана в коде», с видимой escape-последовательностью. Проверим коды и длину символов:
print(ord("\n"), ord("\r")) # 10 13
print(len("\n"), len("\r\n")) # 1 2
То есть \n — это один символ, а \r\n — два символа, идущих подряд. Это важно при подсчете длины и при обрезке строк.
Ошибка: разбиваем текст только по \n
Частая ошибка — резать текст из Windows-источника только по символу \n, забыв про \r.
Неверно:
data = "строка1\r\nстрока2"
print(data.split("\n"))
Фактический вывод:
['строка1\r', 'строка2']
У первого элемента остался «хвост» \r, который потом ломает сравнения и вывод. Исправление — метод splitlines, который понимает все виды переносов сразу:
data = "строка1\r\nстрока2"
print(data.splitlines())
# ['строка1', 'строка2']
# splitlines корректно обрабатывает и смешанные переносы:
print("a\r\nb\rc\nd".splitlines())
# ['a', 'b', 'c', 'd']
Ошибка: лишние пустые строки при записи файла
Второй классический случай — лишние пустые строки при записи CSV или текста в Windows.
Неверно:
import csv
with open("out.csv", "w") as f: # newline не указан
csv.writer(f).writerow(["a", "b"])
Фактический результат в Windows: модуль csv уже пишет \r\n, а текстовый режим файла добавляет к каждому \n еще один \r. Получается \r\r\n, и между строками появляются пустые строки. Исправление — открывать файл с newline="":
import csv
with open("out.csv", "w", newline="") as f:
csv.writer(f).writerow(["a", "b"])
# лишние пустые строки исчезают
Полезно помнить про «универсальные переносы строк»: при чтении файла в текстовом режиме Python сам приводит \r\n и \r к \n. Поэтому при построчном чтении разница между ОС обычно не мешает — проблемы начинаются при записи и в бинарном режиме.
Перенос строки в HTML: тег br и не только
В HTML перенос работает иначе, чем в текстовом файле. Браузер по умолчанию схлопывает любые пробелы и переносы строк из исходного кода в один пробел. Поэтому просто нажать Enter в разметке недостаточно.
Неверно (перенос в исходнике ни на что не влияет):
<p>первая строка
вторая строка</p>
Фактический результат на странице:
первая строка вторая строка
Чтобы получить настоящий перенос, используют одиночный тег <br>. Это пустой (void) элемент: у него нет закрывающего тега и содержимого.
<p>первая строка<br>вторая строка</p>
Результат на странице:
первая строка
вторая строка
В HTML5 достаточно писать <br>; форма <br/> тоже допустима и нужна в XML-совместимой разметке (XHTML), но обязательной уже не является. Тег <br> уместен для смысловых разрывов внутри одного блока — адрес, строки стихотворения, строки в форме. Для отдельных абзацев используют <p>, а не два <br> подряд.
Если же нужно сохранить переносы и пробелы ровно так, как в исходнике (например, вывести фрагмент кода), их не обязательно расставлять тегами — достаточно тега <pre> или CSS-свойства white-space:
.code { white-space: pre-wrap; }
Значение pre сохраняет и переносы, и пробелы; pre-wrap делает то же, но еще и переносит длинные строки по ширине блока; pre-line сохраняет переносы, но схлопывает лишние пробелы. Перенос же длинных слов — отдельная задача свойств overflow-wrap и word-break.
Экранирование и кодировки
Символ переноса не печатается, поэтому в коде его записывают экранированием — через \n и \r. Обратный слэш служебный: "\\n" даст на экране текст \n, а не перенос.
С точки зрения кодировки перенос — это обычный символ таблицы:
- В ASCII и UTF-8 LF занимает один байт
0x0A, CR — один байт0x0D. - В UTF-16 те же символы занимают по два байта:
0x000Aи0x000D.
Проверить это можно так:
print("\n".encode("utf-8")) # b'\n'
print("\n".encode("utf-16-le"))# b'\n\x00'
Поэтому при работе с бинарными данными важно знать кодировку файла: искать байт 0x0A «вслепую» в UTF-16 или в неизвестной кодировке — ненадежно.
Выводы
- Перенос строки — это конкретный управляющий символ в данных, а не просто нажатие Enter: чаще всего
\n(LF, код 10), реже\r(CR, код 13) или пара\r\n(CRLF). - Операционные системы расходятся: Unix, Linux и современная macOS используют
\n, Windows —\r\n, классический Mac OS до 2001 года —\r. Отсюда «висящие»\rи лишние пустые строки при переносе файлов. - В коде надежнее разбивать текст методом
splitlines, а неsplit("\n"), и записывать файлы с учетомnewline, чтобы не удвоить\r. - В HTML переносы из исходника схлопываются в пробел: для видимого разрыва внутри блока нужен тег
<br>, а для сохранения исходного форматирования —<pre>или CSSwhite-space. - В кодировке LF и CR — обычные символы: один байт в ASCII и UTF-8, два байта в UTF-16. При работе с бинарными данными это нужно учитывать.
Где применяется / связь с практикой
С переносами строк сталкивается любой, кто обрабатывает текст: парсит логи и CSV, читает и пишет файлы, генерирует HTML, обменивается данными по сети. Умение отличать LF от CRLF экономит часы отладки, когда «одинаковый» файл ведет себя по-разному на разных машинах.
Отрабатывать это удобнее всего на практике — на реальных файлах и коде. Базовые навыки работы со строками, файлами и кодировками дают на курсе Python Basic: там разбирают чтение и запись файлов, обработку текстовых данных и типичные ошибки вроде тех, что описаны выше. Если хочется сначала присмотреться к формату обучения, посмотрите ближайшие бесплатные вебинары — там можно вживую задать вопросы преподавателям.
Смежные темы: UTF-16: что это такое и чем она отличается от UTF-8, Двоичный код: что это такое, как работает и где применяется, XML: что это такое, как выглядит XML-файл и как с ним работать.
FAQ
Почему на Windows после переноса файла из Linux появляются лишние пустые строки или символ ^M?
Linux размечает строки одиночным \n, а многие Windows-программы ждут \r\n и, наоборот, при обратном переносе добавляют лишний \r, который отображается как ^M. Лечится приведением переносов к нужному виду — инструментами dos2unix/unix2dos или настройкой редактора.
Как узнать, какие переносы строк в конкретном файле — LF или CRLF?
Большинство редакторов (VS Code, Notepad++ и другие) показывают тип переносов в статусной строке и переключают его одним кликом. В терминале это видно через file имя_файла или просмотром байтов через xxd: 0d 0a означает CRLF, одиночный 0a — LF.
Сколько тегов <br> подряд можно ставить, чтобы сделать отступ между абзацами?
Так делать не стоит: <br> предназначен для разрыва внутри одного блока, а не для управления отступами. Для расстояния между абзацами используют отдельные теги <p> и CSS-свойство margin.



