Najlepszy sposób na określenie białych znaków w operacji String.Split


243

Dzielę ciąg znaków na podstawie białych znaków w następujący sposób:

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

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

Definiowanie tablicy char [] w dowolnym miejscu w moim kodzie jest nieprzyjemne. Czy istnieje bardziej skuteczny sposób, który nie wymaga tworzenia tablicy znaków (która jest podatna na błędy, jeśli jest kopiowana w różnych miejscach)?


1
robi to: myStr.Split (''); nie działa?
woolagaroo

4
Jeśli dobrze to zrozumiem, będzie to tylko wyszukiwanie spacji, a nie ogólnych białych znaków

Zobacz także możliwe duplikaty, ale te późniejsze odpowiedzi mają SplitStringOptions. stackoverflow.com/questions/1562981/…
goodeye

Odpowiedzi:


469

Jeśli po prostu zadzwonisz:

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

lub:

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

zakłada się, że biała spacja jest dzielącą postacią. Ze strony string.Split(char[])dokumentacji metody .

Jeśli parametr separatora nullnie zawiera lub nie zawiera znaków, przyjmuje się, że znakami spacji są separatory. Znaki białych znaków są zdefiniowane przez standard Unicode i zwracane, truejeśli zostaną przekazane do Char.IsWhiteSpacemetody.

Zawsze, zawsze, zawsze czytaj dokumentację!


2
Problem z dzieleniem według białych znaków polega na tym, że jeśli trzeba je ponownie złożyć, nie wiadomo, który znak z białych znaków należy odłożyć.
Ross Presser,

19
(char[])nulljest nieco lepszy, ponieważ unika tworzenia nowego obiektu. (Nie można używać nullz żadnym z optionsprzeciążeń).
Artfunkel

5
@RossPresser: Ponowne połączenie łańcucha to zupełnie inny problem, więc nie powiedziałbym, że jest to problem. Ale jeśli wszystko, co musisz zrobić, to złożyć strunę z powrotem dokładnie tak, jak było wcześniej, być może lepiej po prostu zachowaj oryginał.
stakx - nie przyczynia się już

4
Głupie pytanie, ale jeśli używasz null, czy nadal musisz określać, StringSplitOption.RemoveEmptyEntriesczy są one domyślnie ignorowane?
yu_ominae

2
@RossPresser: Ponieważ String.Split nie zapewnia żadnego mechanizmu śledzenia znaków używanych do podziału łańcucha, twoja obserwacja nie jest istotna: nie można osiągnąć tego, czego szukasz za pomocą String.Split, więc wymaga to innych pytań i odpowiedzi.
ToolmakerSteve,

207

Tak, tutaj potrzebna jest jeszcze jedna odpowiedź!

Wszystkie dotychczasowe rozwiązania dotyczą raczej ograniczonej dziedziny kanonicznych danych wejściowych , a mianowicie: pojedynczego spacji między elementami (choć czubek kapelusza na @cherno dla przynajmniej wzmianki o problemie). Ale twierdzę, że we wszystkich oprócz najbardziej niejasnych scenariuszy podzielenie wszystkich z nich powinno dać identyczne wyniki:

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(w dowolnym smaku pokazanym w innych odpowiedziach tutaj) po prostu nie działa dobrze, chyba że podasz RemoveEmptyEntriesopcję z jednym z poniższych:

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

Jak pokazuje ilustracja, pominięcie opcji daje cztery różne wyniki (oznaczone A, B, C i D) w porównaniu do pojedynczego wyniku ze wszystkich czterech danych wejściowych, gdy używasz RemoveEmptyEntries:

String.Split vs Regex.Split

Oczywiście, jeśli nie lubisz korzystać z opcji, skorzystaj z alternatywy regularnej :-)

Regex.Split(myStr, @"\s+").Where(s => s != string.Empty)

4
Wydaje mi się, @RossPresser, że jest to objęte moim kwalifikatorem „we wszystkich, oprócz najbardziej niejasnych scenariuszach”, ponieważ nawet gdybym chciał zrekombinować elementy, trudno byłoby mi znaleźć przypadek, w którym zależy mi na wielu spacjach. Chciałbym formy kanonicznej - jedna przestrzeń między nimi. Dlatego z szacunkiem się nie zgadzam - byłoby to raczej „rzadko złe” niż „zwykle złe”.
Michael Sorens,

1
CapitalizeEveryWord("This is line one.\n \nThis is line three.")
Ross Presser

3
Jeśli naprawdę uważasz, że jest to niejasne, to chyba zgodzimy się z tym nie zgodzić, ale jeśli zostawię tę funkcję poza moim oprogramowaniem, stracę pracę. Użytkownicy lubią swoje treści, aby wyglądały tak, jak chcą.
Ross Presser

4
To powinna być zaakceptowana odpowiedź, ponieważ jest o wiele bardziej kompletna.
Dennis

1
Zastanawiam się, dlaczego dodałeś .Where(s => s != string.Empty)do Regex. Ponieważ podałeś \s+(dowolną liczbę spacji), pomiędzy nimi nie może być pustego elementu.
Jack Miller

44

Zgodnie z dokumentacją :

Jeśli parametr separatora ma wartość NULL lub nie zawiera żadnych znaków, przyjmuje się, że znakami spacji są separatory. Znaki białych znaków są zdefiniowane przez standard Unicode i zwracają wartość true, jeśli zostaną przekazane do metody Char.IsWhiteSpace.

Więc po prostu zadzwoń myStr.Split();Nie musisz niczego przekazywać, ponieważ separator jest paramstablicą.


11

Dlaczego nie używasz ?:

string[] ssizes = myStr.Split(' ', '\t');

2
Nie ma przeciążenia dzielonego, które zajmuje dwa znaki.
takrl

1
@takrl: Spójrz tutaj publiczny ciąg [] Split (params char [] separator) .NET v2
Renatas M.

Tak, to wymaga tablicy znaków. Fragment kodu przekazuje dwa pojedyncze znaki.
takrl

15
@takrl: czy wiesz, co to jest słowo kluczowe params ???
Renatas M.

Całkiem fajnie, +1 za to. Prawdopodobnie osoba, która przegłosowała, też nie wiedziała.
takrl

3

Zauważ, że sąsiadujące białe spacje NIE będą traktowane jako pojedynczy separator, nawet podczas używania String.Split(null). Jeśli którykolwiek z twoich tokenów jest oddzielony wieloma spacjami lub tabulatorami, otrzymasz puste ciągi znaków zwrócone w tablicy.

Z dokumentacji:

Każdy element separatora definiuje oddzielny znak ogranicznika. Jeśli dwa separatory są sąsiadujące lub separator zostanie znaleziony na początku lub na końcu tego wystąpienia, odpowiedni element tablicy zawiera Pusty.


2

Więc nie kopiuj i nie wklejaj! Wyodrębnij funkcję, aby wykonać podział i użyj go ponownie.

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

Ponowne użycie kodu jest twoim przyjacielem.



1

możesz użyć

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

podzielić ciąg.


0

Nie możesz tego zrobić w linii?

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

W przeciwnym razie, jeśli często robisz to dokładnie, zawsze możesz stworzyć stałą lub coś zawierającego tę tablicę znaków.

Jak zauważyli inni, zgodnie z dokumentacją można również użyć nulllub pustej tablicy. Kiedy to zrobisz, automatycznie użyje białych znaków.

var sizes = subject.Split(null);

0

Jeśli problemem jest powtórzenie tego samego kodu, napisz metodę rozszerzenia na klasie String, która zawiera logikę podziału.


1
Przykro mi, to nie odpowiada na pytanie.
p.campbell

p. campbell: Tak, robi: OP poprosił o rozwiązanie, które nie wymaga kopiowania tablicy znaków wszędzie. Oczywistym rozwiązaniem jest utworzenie funkcji do wykonania zadania. Ta odpowiedź wskazuje, że taka funkcja może być metodą rozszerzenia. (Odpowiedź można poprawić, pokazując kod, aby to zrobić ...)
ToolmakerSteve

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.