str::split¶
Level: reference · for working programmers
One line: An iterator over the pieces between the matches — n matches always yield n+1 pieces, which is where every surprising empty string comes from.
Stable since 1.0.0.
split is mechanical, not editorial. It reports the gaps, and a gap with nothing in it is still a gap:
| input | split(',') |
|---|---|
"a,b,c" |
["a", "b", "c"] |
"a,,c" |
["a", "", "c"] — nothing between the two commas |
",a" |
["", "a"] — nothing before the first |
"a," |
["a", ""] — nothing after the last |
"" |
[""] — one piece, no matches |
None of that is the method being unhelpful; the count is forced by the arithmetic. If you want the empties gone, that is a different question and split_whitespace (for prose) or a .filter(|p| !p.is_empty()) ↗ (for anything else) answers it.
An empty pattern is the case that surprises everyone, and it is the same rule with nothing left to hide behind: it matches at every char boundary, so "abc".split("") is four matches and five pieces — ["", "a", "b", "c", ""]. Splitting on nothing works it through, including the boundaries it is not allowed to land on.
Use split for delimited data and split_whitespace for prose. Reaching for the wrong one silently shifts your columns: on "a,,c", dropping the empty makes column 3 become column 2, and nothing errors.
Pieces are borrowed from the original string; nothing is allocated. The pattern is the usual four shapes.
The return value is a lazy iterator, not a list, so println!("{:?}", s.split(":")) prints the Split struct — searcher internals and a cursor — rather than the pieces. .collect::<Vec<&str>>() or a for loop is what produces those; Inside a Split reads the struct field by field.
Example¶
str_split.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.
fn main() {
for input in ["a,b,c", "a,,c", ",a", "a,", ""] {
println!("{:<7} -> {:?}", format!("{input:?}"), input.split(',').collect::<Vec<&str>>());
}
// n matches, n+1 pieces — always.
let s = "the rain in spain";
println!("{} matches, {} pieces", s.matches("in").count(), s.split("in").count());
// The four pattern shapes.
println!("{:?}", "a1b2c".split(char::is_numeric).collect::<Vec<&str>>());
println!("{:?}", "a-b_c".split(&['-', '_'][..]).collect::<Vec<&str>>());
// Dropping empties is your decision, not the method's.
let row = "a,,c";
println!("{:?}", row.split(',').filter(|p| !p.is_empty()).collect::<Vec<&str>>());
println!("columns: {} kept, {} after filtering",
row.split(',').count(),
row.split(',').filter(|p| !p.is_empty()).count());
}
Verified output of str_split.rs — regenerated by tools/run_examples.py, never hand-typed.
"a,b,c" -> ["a", "b", "c"]
"a,,c" -> ["a", "", "c"]
",a" -> ["", "a"]
"a," -> ["a", ""]
"" -> [""]
3 matches, 4 pieces
["a", "b", "c"]
["a", "b", "c"]
["a", "c"]
columns: 3 kept, 2 after filtering
See also¶
str::split_whitespace— the editorial version, for prosestr::split_terminator— drops only a trailing empty piece- Inside a
Split— what{:?}on the iterator is showing you, and whysplit_terminatoris the same struct with one bool flipped str::splitn— stop after n−1 splits and keep the rest wholestr::split_once— exactly two pieces, or nothingstr::matches— the matches instead of the gaps- Splitting on nothing — the empty pattern: five pieces from three characters, and why it is char boundaries rather than byte offsets
str::split in the standard library ↗
Po polsku¶
split nie szuka „słów”, tylko zgłasza przerwy między dopasowaniami, a przerwa, w której nic nie ma, dalej jest przerwą. Stąd cała arytmetyka: n dopasowań to zawsze n+1 kawałków, więc "a,,c" daje ["a", "", "c"], ",a" daje ["", "a"], a pusty tekst "" daje [""] — jeden pusty kawałek, nie zero. To nie jest złośliwość metody, tylko konsekwencja liczenia.
Polskiego czytelnika najczęściej myli tu nawyk z Pythona: tamtejsze bezargumentowe s.split() dzieli po białych znakach i samo wyrzuca puste kawałki, więc łatwo oczekiwać tego samego po str::split(','). Odpowiednikiem bezargumentowego split() jest split_whitespace, a nie split. Pomyłka nie kończy się błędem kompilacji ani paniką — cicho przesuwa kolumny: w "a,,c" po odfiltrowaniu pustych zostają 2 kawałki zamiast 3 i trzecia kolumna staje się drugą. Zasada jest prosta: split do danych z separatorem, split_whitespace do prozy, a wyrzucenie pustych to twoja świadoma decyzja (.filter(|p| !p.is_empty())).
Ostatnia rzecz, która zaskakuje przy pierwszym println!: split zwraca leniwy iterator, więc {:?} wypisze strukturę Split wraz z wnętrznościami wyszukiwarki, a nie kawałki. Dopiero collect::<Vec<&str>>() albo pętla for je pokazuje — i są to wycinki (&str) pożyczone z oryginalnego tekstu, bez żadnej alokacji.
Szukaj po polsku: dzielenie łańcucha znaków w Ruscie · puste elementy po podziale · rust split empty strings · rust split vs split_whitespace