Avatar ·

Как разбить строку на массив строк по символам новой строки в C#?

Всем привет! Я начинающий C# разработчик и столкнулся с такой задачей: мне нужно прочитать текстовый файл и разбить его содержимое на отдельные строки. Каждая строка должна стать элементом массива. Проблема в том, что я не могу правильно выбрать разделитель. Я пробовал использовать `String.Split('\n')`, но это работает не всегда. Например, если файл создан в Windows, строки разделяются комбинацией `\r\n`, и при разбивке только по `\n` у меня остаются символы `\r` в конце каждой строки. Вот мой код: ```csharp string text = "Первая строка\r\nВторая строка\r\nТретья строка"; string[] lines = text.Split('\n'); foreach (var line in lines) { Console.WriteLine($"'{line}'"); } ``` Вывод получается таким: ``` 'Первая строка' 'Вторая строка' 'Третья строка' ``` Обратите внимание на кавычки — в конце первой строки виден символ `\r`, который не удаляется. Я знаю, что можно использовать `StringSplitOptions.RemoveEmptyEntries`, но это не решает проблему с лишними символами. Также пробовал `text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None)`, но это кажется костылём. Есть ли более правильный и элегантный способ разбить строку на строки в .NET? Может быть, есть специальный метод или константа для символов новой строки? Заранее спасибо за помощь! <<>>

Использование String.Split с правильным набором разделителей

Проблема, с которой вы столкнулись, типична для начинающих разработчиков. Дело в том, что разные операционные системы используют разные символы для обозначения конца строки:

  • Windows: \r\n (CR+LF)
  • Unix/Linux/macOS: \n (LF)
  • Старые Mac: \r (CR)

Поэтому разбивка только по одному символу \n приводит к тому, что символ \r остаётся в конце строк. Вот правильное и элегантное решение:

string text = "Первая строка\r\nВторая строка\nТретья строка\rЧетвёртая строка";

// Вариант 1: Использование массива разделителей
string[] lines = text.Split(
    new[] { "\r\n", "\n", "\r" },
    StringSplitOptions.None
);

// Вариант 2: С удалением пустых строк (если есть пустые строки)
string[] lines2 = text.Split(
    new[] { "\r\n", "\n", "\r" },
    StringSplitOptions.RemoveEmptyEntries
);

foreach (string line in lines)
{
    Console.WriteLine($"'{line}'");
}

Лучший способ: Использование StringReader

Начиная с .NET Framework 2.0, существует более правильный способ — класс StringReader. Он автоматически обрабатывает все варианты переносов строк:

using System.IO;

string text = "Первая строка\r\nВторая строка\nТретья строка\rЧетвёртая строка";

List<string> linesList = new List<string>();
using (StringReader reader = new StringReader(text))
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        linesList.Add(line);
    }
}

string[] lines = linesList.ToArray();

Самый современный способ (.NET 6+)

Начиная с .NET 6, появился удобный метод SplitLines(), который делает всё за вас:

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

Важно: Метод SplitLines() доступен только в .NET 6 и новее. Если вы используете более старую версию, используйте StringReader.

Что выбрать?

  • Если вы используете .NET 6+: используйте SplitLines() — это самый простой и читаемый вариант.
  • Если у вас старая версия .NET: используйте StringReader — он надёжно обрабатывает все варианты переносов и не оставляет лишних символов.
  • Если нужна максимальная производительность: используйте String.Split с массивом разделителей, но помните, что этот вариант менее читаемый.

В вашем случае я рекомендую StringReader, так как он не зависит от версии .NET и гарантированно корректно обрабатывает любой текст, независимо от того, на какой платформе он был создан.

<<>>

Альтернативный подход: Регулярные выражения

Если вам нужно больше контроля над процессом разбивки, можно использовать регулярные выражения. Это особенно полезно, если в строках могут быть нестандартные разделители или вы хотите дополнительно обработать текст:

using System.Text.RegularExpressions;

string text = "Первая строка\r\nВторая строка\nТретья строка\rЧетвёртая строка";

// Разбиваем по всем возможным комбинациям переносов строк
string[] lines = Regex.Split(text, @"\r\n|\n|\r");

// С удалением пустых строк
string[] lines2 = Regex.Split(text, @"\r\n|\n|\r")
                       .Where(s => !string.IsNullOrEmpty(s))
                       .ToArray();

foreach (string line in lines)
{
    Console.WriteLine($"'{line}'");
}

Плюсы: Гибкость — можно легко изменить шаблон для обработки специфических случаев (например, если нужно игнорировать переносы внутри кавычек).
Минусы: Меньшая производительность по сравнению с StringReader или SplitLines(), а также более сложный синтаксис для начинающих.

Если производительность не критична (например, вы обрабатываете небольшие объёмы данных), этот подход вполне рабочий. Для больших файлов лучше использовать StringReader.