Лучший способ указать пробел в операции String.Split

243

Я разделяю строку на основе пробелов следующим образом:

string myStr = "The quick brown fox jumps over the lazy dog";

char[] whitespace = new char[] { ' ', '\t' };
string[] ssizes = myStr.Split(whitespace);

Утомительно определять массив char [] везде в моем коде, я хочу сделать это. Есть ли более эффективный способ, который не требует создания массива символов (который подвержен ошибкам при копировании в разные места)?

Джон Сондерс
источник
1
делает это: myStr.Split (''); не работает?
woolagaroo
4
Если я правильно понимаю, это будет искать только пробел, а не общий пробел
Смотрите также возможные дубликаты, но эти более поздние ответы имеют SplitStringOptions. stackoverflow.com/questions/1562981/…
goodeye

Ответы:

469

Если вы просто позвоните:

string[] ssize = myStr.Split(null);

или:

string[] ssize = myStr.Split(new char[0]);

тогда предполагается, что пробел является символом расщепления. Со string.Split(char[])страницы документации метода .

Если параметр разделителя равен nullили не содержит символов, символами пробела считаются разделители. Пробельные символы определяются стандартом Unicode и возвращаются, trueесли они переданы Char.IsWhiteSpaceметоду.

Всегда, всегда, всегда читайте документацию!

Ясон
источник
2
Проблема с разделением по пробелам состоит в том, что если вам нужно снова собрать их вместе, вы не знаете, какой символ пробела ставить обратно.
Росс Прессер,
19
(char[])nullнемного лучше, так как избегает создания нового объекта. (Вы не можете использовать nullс любой из optionsперегрузок).
Артфункель
5
@RossPresser: собрать строку обратно - это совсем другая проблема, поэтому я бы не сказал, что это проблема здесь. Но если все, что вам нужно сделать, это собрать строку обратно точно так, как это было раньше, то, возможно, лучше просто сохранить оригинал.
stakx - больше не вносит вклад
4
Глупый вопрос, но если вы используете null, вам все равно нужно указать StringSplitOption.RemoveEmptyEntriesили они по умолчанию игнорируются?
yu_ominae
2
@RossPresser: Поскольку String.Split не предоставляет никакого механизма для отслеживания символов, используемых для разделения строки, ваше наблюдение не имеет значения: невозможно достичь того, что вы ищете, используя String.Split, поэтому для этого требуются другие вопросы и ответы.
ToolmakerSteve
207

Да, здесь нужен еще один ответ!

Пока что все решения направлены на довольно ограниченную область канонического ввода , а именно: один символ пробела между элементами (хотя на кону @cherno хотя бы упомянул проблему). Но я утверждаю, что во всех сценариях, кроме самых неясных, их разделение должно давать одинаковые результаты:

string myStrA = "The quick brown fox jumps over the lazy dog";
string myStrB = "The  quick  brown  fox  jumps  over  the  lazy  dog";
string myStrC = "The quick brown fox      jumps over the lazy dog";
string myStrD = "   The quick brown fox jumps over the lazy dog";

String.Split(в любом из вариантов, показанных в других ответах здесь) просто не будет работать хорошо, если вы не добавите RemoveEmptyEntriesодин из следующих вариантов:

myStr.Split(new char[0], StringSplitOptions.RemoveEmptyEntries)
myStr.Split(new char[] {' ','\t'}, StringSplitOptions.RemoveEmptyEntries)

Как показано на иллюстрации, если вы не укажете эту опцию, вы получите четыре разных результата (помеченных как A, B, C и D) по сравнению с одним результатом для всех четырех входов при использовании RemoveEmptyEntries:

String.Split против Regex.Split

Конечно, если вам не нравится использование опций, просто используйте альтернативу регулярному выражению :-)

Regex.Split(myStr, @"\s+").Where(s => s != string.Empty)
Майкл Соренс
источник
4
Я думаю, @RossPresser, что это покрыто моим классификатором «по всем, кроме самых непонятных сценариев», потому что даже при желании рекомбинировать элементы мне было бы тяжело иметь дело с несколькими пробелами. Я хотел бы каноническую форму - один пробел между каждым. Так что я с уважением не согласен - это будет «редко неправильно», а не «обычно неправильно».
Майкл Соренс
1
CapitalizeEveryWord("This is line one.\n \nThis is line three.")
Росс Прессер
3
Если вы действительно думаете, что это неясно, тогда, я думаю, нам придется согласиться не соглашаться, но если я оставлю эту функцию вне своего программного обеспечения, я потеряю свою работу. Пользователям нравится, что их контент выглядит так, как он хочет.
Росс Прессер
4
Это должен быть принятый ответ, так как он гораздо более полный.
Деннис
1
Мне интересно, почему вы добавили .Where(s => s != string.Empty)в Regex. Поскольку вы указываете \s+(любое количество пробелов), между ними не может быть пустых элементов.
Джек Миллер
44

Согласно документации :

Если параметр разделителя имеет значение NULL или не содержит символов, символы пробела считаются разделителями. Пробельные символы определяются стандартом Unicode и возвращают true, если они передаются в метод Char.IsWhiteSpace.

Так что просто позвоните. myStr.Split();Нет необходимости передавать что-либо, потому что разделитель - это paramsмассив.

ageektrapped
источник
11

Почему вы не используете ?:

string[] ssizes = myStr.Split(' ', '\t');
Ренатас М.
источник
2
Нет перегрузки Split, которая занимает два символа.
Такрл
1
@takrl: Посмотрите здесь открытую строку [] Split (params char [] separator) .NET v2
Ренатас М.
Да, это занимает массив символов. Ваш фрагмент кода передает два отдельных символа.
Такрл
15
@takrl: ты знаешь, что такое ключевое слово params ???
Ренатас М.
Довольно круто, +1 за это. Вероятно, человек, который проголосовал, тоже не знал.
Такрл
3

Обратите внимание, что соседние пробелы НЕ будут рассматриваться как один разделитель, даже при использовании String.Split(null). Если какие-либо из ваших токенов разделены несколькими пробелами или табуляциями, вы получите пустые строки, возвращенные в ваш массив.

Из документации:

Каждый элемент разделителя определяет отдельный символ разделителя. Если два разделителя являются смежными или в начале или конце этого экземпляра найден разделитель, соответствующий элемент массива содержит значение Empty.

Чёрно
источник
2

Так что не копируйте и не вставляйте! Извлеките функцию для разделения и используйте ее снова.

public static string[] SplitWhitespace (string input)
{
    char[] whitespace = new char[] { ' ', '\t' };
    return input.Split(whitespace);
}

Повторное использование кода ваш друг.

Тим Роджерс
источник
1

ты можешь использовать

var FirstString = YourString.Split (). First ();

разбить строку.

Haxer
источник
0

Разве вы не можете сделать это встроенным?

var sizes = subject.Split(new char[] { ' ', '\t' });

В противном случае, если вы будете делать именно это часто, вы всегда можете создать константу или что-то, содержащее этот массив символов.

Как отметили другие, вы можете в соответствии с документацией также использовать nullили пустой массив. Когда вы это сделаете, он будет автоматически использовать пробельные символы.

var sizes = subject.Split(null);
Svish
источник
0

Если повторение того же кода является проблемой, напишите метод расширения в классе String, который инкапсулирует логику разделения.

Xhalent
источник
1
Это на самом деле не отвечает на вопрос, извините.
p.campbell
п. Кэмпбелл: Да, это так: OP запросил решение, которое не требует повсеместного копирования массива символов. Очевидное решение - создать функцию для выполнения задачи. Этот ответ указывает на то, что такая функция может быть методом расширения. (Ответ может быть улучшен, показывая код, чтобы сделать это ...)
ToolmakerSteve