TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #3230 1.6K
День 2698. #ЗаметкиНаПолях
Перенос Строки — Это не Только
\r и \n
Когда мы говорим о символах переноса строки, большинство разработчиков думают о \r\n (Windows) и \n (Unix). В большинстве случаев это работает, но это не полная картина.

Юникод и несколько механизмов регулярных выражений распознают дополнительные символы переноса строки. Если ваше приложение обрабатывает пользовательский ввод, логи, CSV-файлы или кроссплатформенные данные, это может иметь большее значение, чем вы думаете.

Переносы строк, которые следует знать
Наиболее распространённые символы завершения строки:
\r\n (CRLF, U+000D U+000A)
\n (LF, U+000A)
\r (CR, U+000D)


Unicode Technical Report #18 (RL1.6) также отмечает эти ограничители:
\u0085 (NEL, Next Line)
\u2028 (LS, Line Separator)
\u2029 (PS, Paragraph Separator)

Вы также можете считать эти пробельные символы переносами строки в некоторых контекстах:
\v (VT, Vertical Tab, U+000B)
\f (FF, Form Feed, U+000C)

Поэтому полноценное «разбиение по строкам» не должно подразумевать только CR и LF.

Почему это важно в реальном коде
Эти символы могут поступать из:
- Скопированного текста из офисных программ или устаревших систем;
- Файлов, преобразованных с помощью нескольких этапов кодирования и нормализации.

Если вы разделяете текст только по символам \r\n или \n, некоторые записи могут остаться объединёнными в одну строку, что может нарушить синтаксический анализ, проверку или формирование отчётов.

Более безопасный синтаксический анализ в .NET
Если вам нужно разделить текст на строки, отдавайте предпочтение шаблону, который обрабатывает последовательности символов новой строки Unicode.
using System.Text.RegularExpressions;

string input = "A\u2028B\u0085C\r\nD";
string[] lines = Regex.Split(input, @"(?>\r\n|[\n\v\f\r\u0085\u2028\u2029])");

// lines = ["A", "B", "C", "D"]

В .NET шаблон \R пока не поддерживается, поэтому приходится использовать более явный шаблон.

Если вы хотите избежать аллокации массива строк и строковой переменной на каждую строку, в .NET 9 представлен Regex.EnumerateSplits:
using System;
using System.Text.RegularExpressions;

ReadOnlySpan<char> input = "A\u2028B\u0085C\r\nD";

foreach (Range split in Regex.EnumerateSplits(input, @"(?>\r\n|[\n\v\f\r\u0085\u2028\u2029])"))
{
ReadOnlySpan<char> line = input[split];
ProcessLine(line);
}

static void ProcessLine(ReadOnlySpan<char> line)
{
// обработка line без аллокаций
}


Для нормализации .NET также предоставляет метод string.ReplaceLineEndings, который полезен, когда необходимо преобразовать все символы конца строки в единое соглашение перед обработкой:
string input = "A\u2028B\u0085C\r\nD";
string normalized = input.ReplaceLineEndings("\n");
string[] lines = normalized.Split('\n');

// normalized = "A\nB\nC\nD"
// lines = ["A", "B", "C", "D"]


Источник:
https://www.meziantou.net/new-lines-are-more-than-r-and-n.htm
  • 👍 8
  • 👎 1
More from @netdeveloperdiary
  1. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
  2. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
  3. Sep 25, 2026День 2795. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Начало Проблема с позиц…
  4. Sep 24, 2026День 2794. #Оффтоп #Здоровье Сегодня будет необычный пост. Завтра в Москве стартует конфер…
  5. Sep 23, 2026День 2793. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
  6. Sep 22, 2026День 2792. #ЗаметкиНаПолях #SQL 10 Редких Возможностей SQL, Которые Стоит Знать Каждому. Ч…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →