Найпростіший спосіб розділити рядок на нові рядки в .NET?


806

Мені потрібно розділити рядок на нові рядки в .NET, і єдиний спосіб, який я знаю, щоб розділити рядки, це метод Split . Однак це не дозволить мені (легко) розділитись на новий рядок, тож який найкращий спосіб це зробити?


2
Чому б і ні? Просто розділився на System.Environment.NewLine
aviraldg

16
Але вам потрібно загорнути його в рядок [] і додати додатковий аргумент і ... він просто відчуває незграбність.
RCIX

Відповіді:


1413

Для поділу на рядок потрібно використовувати перевантаження, яке приймає масив рядків:

string[] lines = theText.Split(
    new[] { Environment.NewLine },
    StringSplitOptions.None
);

Редагувати:
Якщо ви хочете обробляти різні типи розривів рядків у тексті, ви можете використовувати можливість зіставлення декількох рядків. Це буде правильно розділено на будь-який тип розриву рядків і збереже порожні рядки та пробіли в тексті:

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

3
@RCIX: Надсилання правильних параметрів методу трохи незручно, оскільки ви використовуєте його для чогось набагато простішого, ніж для чого він здатний. Принаймні, це там, перед рамкою 2 вам довелося використовувати регулярний вираз або побудувати власну рутину поділу, щоб розділити на рядок ...
Guffa

4
@Leandro: Environment.NewLineВластивість містить новий рядок за замовчуванням для системи. Наприклад, для системи Windows "\r\n".
Guffa

3
@Leandro: Одне здогадування було б, що програма розбивається, \nзалишаючи \rв кінці кожного рядка, а потім виводить рядки \r\nміж ними.
Guffa

3
@Samuel: Послідовності \rі \nescape (серед інших) мають особливе значення для компілятора C #. У VB немає цих послідовностей евакуації, тому там замість них використовуються ці константи.
Guffa

2
Якщо ви хочете приймати файли з безлічі різних ОС, ви також можете додати "\ n \ r" до початку та "\ r" до кінця списку роздільників. Я не впевнений, що варто діяти хітом. ( en.wikipedia.org/wiki/Newline )
користувач420667

121

Що з використанням a StringReader?

using (System.IO.StringReader reader = new System.IO.StringReader(input)) {
    string line = reader.ReadLine();
}

13
Це мій улюблений. Я завернув
Ronnie Overby

3
Це єдине нерегексичне рішення, яке я знайшов для .netcf 3.5
Carl

8
Особливо приємно, коли вхід великий, а його копіювання в масив стає повільним / великою є пам'ять.
Алехандро

1
Як написано, ця відповідь читає лише перший рядок. Дивіться відповідь Стіва Купера щодо whileциклу, який слід додати до цієї відповіді.
ToolmakerSteve

48

Ви повинні мати можливість легко розділити рядок, як-от так:

aString.Split(Environment.NewLine.ToCharArray());

46
У системі, яка не є * nix, яка розділиться на окремі символи рядка Newline, тобто символи CR та LF. Це спричинить додатковий порожній рядок між кожним рядком.
Гуффа

Виправте мене, якщо я помиляюся, але чи не буде це розділення на символи \ і n?
RCIX

7
@RCIX: Ні, коди \ r та \ n являють собою поодинокі символи. Рядок "\ r \ n" - це два символи, а не чотири символи.
Гуффа

10
якщо ви додасте параметр StringSplitOptions.RemoveEmptyEntries, то це буде працювати бездоганно.
Рубен

18
@Ruben: Ні, не буде. Серж уже запропонував це у своїй відповіді, і я вже пояснив, що це також видалить порожні рядки з оригінального тексту, які слід зберегти.
Гуффа

34

Постарайтеся уникати використання string.Split для загального рішення, тому що ви будете використовувати більше пам’яті скрізь, де ви використовуєте функцію - оригінальну рядок і розділену копію, як у пам'яті. Повірте мені, що це може бути однією пекельною проблемою, коли ви починаєте масштабувати - запустіть 32-бітну пакетну обробку додатка, що обробляє документи на 100 МБ, і ви будете лайно на восьми паралельних потоках. Не те, щоб я там був раніше ...

Натомість використовуйте такий ітератор;

    public static IEnumerable<string> SplitToLines(this string input)
    {
        if (input == null)
        {
            yield break;
        }

        using (System.IO.StringReader reader = new System.IO.StringReader(input))
        {
            string line;
            while( (line = reader.ReadLine()) != null)
            {
                yield return line;
            }
        }
    }

Це дозволить зробити циклічніший цикл навколо даних;

foreach(var line in document.SplitToLines()) 
{
    // one line at a time...
}

Звичайно, якщо ви хочете все це в пам'яті, ви можете це зробити;

var allTheLines = document.SplitToLines.ToArray();

Я там був ... (розбір великих файлів HTML і втрата пам’яті). Так, уникайте string.Split. Використання string.Split може призвести до використання великої кучі об’єктів (LOH) - але я не впевнений у цьому на 100%.
Пітер Мортенсен

Якщо ви зробили SplitToLines статичним методом (який, здається, вам є дд), то як це зробити, blah.SplitToLines.. наприклад document.SplitToLines...?
барлоп

ах, я бачу, ви ввели thisформальні параметри, роблячи це метод розширення.
барлоп

26

На основі відповіді Гуффи в класі розширень використовуйте:

public static string[] Lines(this string source) {
    return source.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
}

9

Для змінної рядка s:

s.Split(new string[]{Environment.NewLine},StringSplitOptions.None)

Для цього використовується визначення вашого кінця рядка. У Windows закінчення рядків - це CR-LF (повернення каретки, канал рядка) або символи втечі C # \r\n.

Це надійне рішення, адже якщо ви рекомбінуєте рядки String.Join, це дорівнює вашій початковій рядку:

var lines = s.Split(new string[]{Environment.NewLine},StringSplitOptions.None);
var reconstituted = String.Join(Environment.NewLine,lines);
Debug.Assert(s==reconstituted);

Що не робити:

  • Використовуйте StringSplitOptions.RemoveEmptyEntries, тому що це порушить розмітку, наприклад, Markdown, коли порожні рядки мають синтаксичне призначення.
  • Розділіть на роздільник new char[]{Environment.NewLine}, оскільки в Windows це створить один порожній рядовий елемент для кожного нового рядка.

В основному така ж відповідь, що і найкраще оцінений, прийнятий, але у нього є хороший одиничний тест і застереження.
vapcguy

8

Регекс - це також варіант:

    private string[] SplitStringByLineFeed(string inpString)
    {
        string[] locResult = Regex.Split(inpString, "[\r\n]+");
        return locResult;
    }

7
Якщо ви хочете , щоб відповідати лінії точно, зберігаючи порожні рядки, це регулярний вираз рядок буде краще: "\r?\n".
Rory O'Kane

7

Я просто думав, що додаю свої двобітні, тому що інші рішення цього питання не підпадають під класифікацію коду для багаторазового використання та не є зручними.

Наступний блок коду розширює stringоб'єкт, щоб він був доступний як природний метод при роботі з рядками.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.Collections.ObjectModel;

namespace System
{
    public static class StringExtensions
    {
        public static string[] Split(this string s, string delimiter, StringSplitOptions options = StringSplitOptions.None)
        {
            return s.Split(new string[] { delimiter }, options);
        }
    }
}

Тепер ви можете використовувати .Split()функцію з будь-якого рядка наступним чином:

string[] result;

// Pass a string, and the delimiter
result = string.Split("My simple string", " ");

// Split an existing string by delimiter only
string foo = "my - string - i - want - split";
result = foo.Split("-");

// You can even pass the split options parameter. When omitted it is
// set to StringSplitOptions.None
result = foo.Split("-", StringSplitOptions.RemoveEmptyEntries);

Щоб розділити на новий рядок символ, просто пропустіть "\n"або "\r\n"як параметр-роздільник.

Коментар: Було б непогано, якби Microsoft здійснив це перевантаження.


Environment.Newlineкращим є жорстке кодування \nабо \r\n.
Майкл Блекберн

3
@MichaelBlackburn - це невірне твердження, оскільки немає контексту. Environment.Newlineпризначена для сумісності між платформами, а не для роботи з файлами, що використовують інші закінчення рядків, ніж поточна операційна система. Дивіться тут для отримання додаткової інформації , тому це дійсно залежить від того, з чим працює розробник. Використання Environment.Newlineгарантує відсутність узгодженості типу повернення рядків між ОС, де "жорстке кодування" дає розробнику повний контроль.
Прем'єр-міністр Краанг

2
@MichaelBlackburn - Не потрібно тобі бути грубим. Я просто надав інформацію. .NewlineЦе не магія, під кришкою - це лише рядки, як зазначено вище, на основі комутатора, якщо він працює на Unix або на Windows. Найбезпечніша ставка - спочатку зробити заміну рядка для всіх "\ r \ n", а потім розділити на "\ n". Якщо використовується .Newlineпомилка, це коли ви працюєте з файлами, які зберігаються іншими програмами, які використовують інший метод для розривів рядків. Він добре працює, якщо ви знаєте щоразу, коли файл для читання завжди використовує перерви у рядку вашої поточної ОС.
Прем'єр-міністр Краанг

Тож те, що я чую, є найбільш читабельним способом (можливо, більшим використанням пам'яті) foo = foo.Replace("\r\n", "\n"); string[] result = foo.Split('\n');. Я правильно розумію, що це працює на всіх платформах?
Джон Доу

4

Зараз я використовую цю функцію (на основі інших відповідей) у VB.NET:

Private Shared Function SplitLines(text As String) As String()
    Return text.Split({Environment.NewLine, vbCrLf, vbLf}, StringSplitOptions.None)
End Function

Спершу він намагається розділити на місцевій платформі новий рядок, а потім переходить до кожної можливої ​​нової лінії.

Поки мені це було потрібно лише в одному класі. Якщо це зміниться, я, мабуть, це зроблюPublic і переміщу його в клас корисності, а можливо, навіть зроблю його методом розширення.

Ось як приєднатись до резервного копіювання рядків, на користь:

Private Shared Function JoinLines(lines As IEnumerable(Of String)) As String
    Return String.Join(Environment.NewLine, lines)
End Function

@Samuel - зверніть увагу на цитати. Вони насправді мають таке значення. "\r"= повернути. "\r\n"= повернення + новий рядок. (перегляньте цю публікацію та прийняте тут рішення
Краанг Прем'єр

@Kraang Хм .. Я давно не працював з .NET. Я був би здивований, якби багато людей нагорі проголосували неправильною відповіддю. Я бачу, що я також прокоментував відповідь Гуффи і там отримав роз'яснення. Я видалив свій коментар до цієї відповіді. Дякую за голову вгору
Самуїл

2

Ну, насправді розкол повинен зробити:

//Constructing string...
StringBuilder sb = new StringBuilder();
sb.AppendLine("first line");
sb.AppendLine("second line");
sb.AppendLine("third line");
string s = sb.ToString();
Console.WriteLine(s);

//Splitting multiline string into separate lines
string[] splitted = s.Split(new string[] {System.Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);

// Output (separate lines)
for( int i = 0; i < splitted.Count(); i++ )
{
    Console.WriteLine("{0}: {1}", i, splitted[i]);
}

2
Параметр RemoveEmptyEntries видалить порожні рядки з тексту. Це може бути бажано в деяких ситуаціях, але простий розкол повинен зберігати порожні рядки.
Гуффа

так, ти маєш рацію, я просто зробив це припущення, що ... ну, порожні рядки не цікаві;)
MaciekTalaska

1
string[] lines = text.Split(
  Environment.NewLine.ToCharArray(), 
  StringSplitOptions.RemoveEmptyStrings);

У RemoveEmptyStrings переконається, що у вас немає порожніх записів через \ n після \ r

(Відредагуйте, щоб відобразити коментарі :) Зауважте, що вона також відкидає справжні порожні рядки в тексті. Зазвичай це те, що я хочу, але це може бути не вашою вимогою.


Параметри RemoveEmptyStrings також видалять порожні рядки, тому він не працює належним чином, якщо в тексті є порожні рядки.
Гуффа

Можливо, ви хочете зберегти справжні порожні рядки: \ r \ n \ r \ n
тонкий

0

Я не знав про Environment.Newline, але, мабуть, це дуже вдале рішення.

Моя спроба була б:

        string str = "Test Me\r\nTest Me\nTest Me";
        var splitted = str.Split('\n').Select(s => s.Trim()).ToArray();

Додатковий .Trim видаляє будь-який \ r або \ n, який може бути присутнім (наприклад, коли у Windows, але розділяє рядок із символами os x newline). Напевно, не найшвидший метод.

Редагувати:

Як правильно зазначалося в коментарях, це також видаляє пробіли на початку рядка або перед подачею нового рядка. Якщо вам потрібно зберегти цей пробіл, використовуйте один з інших варіантів.


Обрізка також видалить пробіли на початку та в кінці рядків, наприклад відступ.
Гуффа

".Trim видаляє будь-який \ r або \ n, який може бути присутнім" - ouch. Чому б замість цього не написати надійний код?
bzlm

Можливо, я помилився з цим питанням, але це було / не ясно, що пробіл повинен бути збережений. Звичайно, ви праві, Trim () також видаляє пробіл.
Макс

1
@Max: Вау, зачекайте, поки я скажу своєму начальникові, що кодом дозволено робити все, що конкретно не виключається в специфікації ...;)
Guffa

-2

Нерозумна відповідь: пишіть у тимчасовий файл, щоб ви могли користуватися поважними File.ReadLines

var s = "Hello\r\nWorld";
var path = Path.GetTempFileName();
using (var writer = new StreamWriter(path))
{
    writer.Write(s);
}
var lines = File.ReadLines(path);

1
Уникайте var, оскільки він не визначає тип змінної, тому ви, можливо, не розумієте, як використовувати цей об’єкт або що цей об'єкт являє собою. Крім того, це показує написання рядків і навіть не вказує ім'я файлу, тому я сумніваюся, що це спрацює. Потім при читанні шлях до файлу знову не вказується. Якщо припустити, що pathце C:\Temp\test.txt, ви повинні мати string[] lines = File.ReadLines(path);.
vapcguy

1
@vapcguy, що я щойно прочитав? - Я б рекомендував перечитати публікацію або налагодити її в консольній програмі, оскільки все, що ви сказали, - це неправильно | шлях встановлений на Path.GetTempFileName | var - поширене та рекомендоване визначення у C # - до речі, він визначає тип змінної ...... EDIT: Я не кажу, що це хороше рішення
koanbock

@koanbock Добре, тому я шукав Path.GetTempFileName msdn.microsoft.com/en-us/library/…, і він говорить, що створює файл з нульовим байтом і повертає "повний шлях цього файлу". Я міг би посягнутись, що я пробував це раніше, і він дав виняток, оскільки він не знайшов файл, але йому було повернуто місце папки. Я знаю аргументи для використання var, але я б сказав, що НЕ рекомендується, оскільки він не показує, що таке об'єкт змінної. Це обтяжує це.
vapcguy

-3
using System.IO;

string textToSplit;

if (textToSplit != null)
{
    List<string> lines = new List<string>();
    using (StringReader reader = new StringReader(textToSplit))
    {
        for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
        {
            lines.Add(line);
        }
    }
}

-5

Насправді дуже просто.

VB.NET:

Private Function SplitOnNewLine(input as String) As String
    Return input.Split(Environment.NewLine)
End Function

C #:

string splitOnNewLine(string input)
{
    return input.split(environment.newline);
}

4
Абсолютно неправильно і не працює. Плюс у C # - це Environment.NewLineяк у VB.
vapcguy

Див. Ідентифікатор кінцевої лінії у VB.NET? для різних варіантів нового рядка.
Пітер Мортенсен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.