Перенос Строки — Это не Только
\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