Разбиваем строку на строки в .NET: 5 фатальных ошибок и их решение

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Почему простое разбиение строки становится головной болью?

Казалось бы, что может быть проще, чем разбить текст на строки? Любой новичок в C# скажет: «Используй string.Split('\n') — и дело в шляпе!». Но на практике именно эта, на первый взгляд, тривиальная задача становится источником сотен багов, которые мы видим на Stack Overflow. Тысячи разработчиков ежедневно задают один и тот же вопрос: «split a string on newlines in .NET — а почему у меня не работает?».

В этой статье мы не просто дадим готовый рецепт. Мы пройдемся по граблям, на которые наступали даже опытные программисты. Вы узнаете, как правильно разбивать строки с учетом разных платформ, кодировок и неожиданных форматов файлов. Пристегнитесь — будет больно и полезно.

Топ-5 ошибок при разбиении строки на строки в C#

1. Наивное использование '\n' — убийца кроссплатформенности

Самая распространенная ошибка — жестко закодировать символ новой строки. Многие пишут:

string text = "Первая строка\nВторая строка\nТретья строка";
string[] lines = text.Split('\n');

Проблема: В Windows стандартный разделитель — "\r\n" (возврат каретки + перевод строки), а в Linux/macOS — просто '\n'. Если вы получите текст из файла, созданного в Windows, ваш код оставит символ '\r' в конце каждой строки. Результат: "Первая строка\r" — и ваш парсер сходит с ума.

Решение: Используйте StringSplitOptions.RemoveEmptyEntries и разбивайте по всем возможным вариантам:

string[] lines = text.Split(new[] { "\r\n", "\r", "\n" }, 
    StringSplitOptions.RemoveEmptyEntries);

Этот код корректно обработает любую комбинацию символов перевода строки.

2. Игнорирование Environment.NewLine в рантайме

Если вы пишете код, который будет работать и на Windows, и на Linux (например, ASP.NET Core приложение), нельзя полагаться на константы. Environment.NewLine возвращает правильный разделитель для текущей ОС, но не гарантирует, что входные данные соответствуют этой ОС.

Ловушка: Вы пишете:

string[] lines = text.Split(Environment.NewLine);

Это сработает, только если текст был создан на той же платформе. Если вы загружаете файл, скачанный из интернета (где строки могут быть в стиле Unix), — привет, баг!

Лучшая практика: Всегда используйте универсальный метод из пункта 1, независимо от платформы.

3. Забыли про StringSplitOptions.RemoveEmptyEntries

Посмотрите на этот код:

string text = "Строка1\n\nСтрока3";
string[] lines = text.Split('\n');
// Результат: ["Строка1", "", "Строка3"]

Пустая строка между "Строка1" и "Строка3" появляется из-за двух последовательных символов новой строки. Если вы обрабатываете CSV, логи или конфигурационные файлы, пустые строки могут сломать логику.

Решение:

string[] lines = text.Split(new[] { "\r\n", "\r", "\n" }, 
    StringSplitOptions.RemoveEmptyEntries);
// Результат: ["Строка1", "Строка3"]

Но будьте осторожны: если пустые строки имеют значение (например, в форматированном тексте), используйте StringSplitOptions.None.

4. Проблема с последним символом новой строки

Представьте, что у вас есть файл с текстом:

Строка1\nСтрока2\n

Многие ожидают, что после разбиения получится массив из двух элементов. Но:

string[] lines = text.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
// Результат: ["Строка1", "Строка2"]

Всё верно. А если убрать RemoveEmptyEntries?

string[] lines = text.Split('\n');
// Результат: ["Строка1", "Строка2", ""]

Третья пустая строка! Она появляется из-за завершающего символа '\n'. Это частая причина ошибок при подсчете строк или итерации по массиву.

Совет: Всегда явно указывайте StringSplitOptions и проверяйте, нужны ли вам пустые записи в конце.

5. Разбиение по '\n' в строках с '\r\n'

Это классика. Файл из Windows:

Строка1\r\nСтрока2\r\nСтрока3

Вы делаете:

string[] lines = text.Split('\n');
// Результат: ["Строка1\r", "Строка2\r", "Строка3"]

Теперь в каждой строке есть лишний символ '\r'. Если вы попытаетесь сравнить строки или записать их в базу данных, получите неожиданные результаты.

Исправление: Используйте StringSplitOptions.TrimEntries (доступно в .NET 5+):

string[] lines = text.Split(new[] { '\r', '\n' }, 
    StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);

Или старый добрый вариант с Trim() после разбиения.

Идеальное решение: совмещаем все лучшее

Как должен выглядеть production-ready код для разбиения строки на строки в C#? Вот универсальный метод, который я использую в своих проектах:

public static string[] SplitIntoLines(this string text)
{
    if (string.IsNullOrEmpty(text))
        return Array.Empty<string>();

    return text.Split(
        new[] { "\r\n", "\r", "\n" },
        StringSplitOptions.RemoveEmptyEntries
    );
}

Почему это хорошо:

  • Extension method — удобно вызывать на любой строке
  • Проверка на null/пустоту — не упадет с исключением
  • Все варианты разделителей — работает с любым текстом
  • RemoveEmptyEntries — избавляет от мусора

Пример использования:

string data = "Строка1\r\nСтрока2\nСтрока3\rСтрока4";
foreach (var line in data.SplitIntoLines())
{
    Console.WriteLine($"- {line}");
}
// Вывод:
// - Строка1
// - Строка2
// - Строка3
// - Строка4

Блоги

Рекомендаций по книгам