Skip to content
Select theme

How to split a string

Short answer: str::split takes a separator and returns an iterator of &str slices — text.split(',') for a fixed separator, text.split_whitespace() for words, text.split_once('=') when you only need the first cut.

From a fresh project — cargo new split-demo, then replace src/main.rs with each block below and run it with cargo run. The project name only shows up in cargo’s own output; nothing else on this page depends on it.

alpha
beta
gamma

split is lazy. It hands back an iterator of slices borrowed from line, and no text is copied until something consumes the iterator. Ask for a Vec and the pieces land in one:

["alpha", "beta", "gamma"]

The separator doesn’t have to be a single character. A &str of any length works, and so does a char array when there are several:

["alpha", "beta", "gamma"]

split is a method on str, so a String can be split the same way. The slices borrow from it.

split is mechanical: every match of the separator is a cut, and the piece between two cuts can be empty. A separator at the start or end of the string leaves an empty piece there too:

[alpha]
[]
[beta]
[]

For a CSV line that is usually right: an empty field should stay empty. When it isn’t, split_terminator drops the piece a trailing separator produces, and only that one:

["alpha", "", "beta"]

Splitting on whitespace is common enough to have its own method. split_whitespace skips runs of any whitespace — spaces, tabs, newlines — and never returns an empty piece:

["alpha", "beta", "gamma"]

It splits on Unicode whitespace, so a non-breaking space counts as one. The empty string shows the difference between the two methods: "".split(',').count() is 1, one empty piece, while "".split_whitespace().count() is 0.

Config and header lines are key=value. split_once cuts at the first occurrence of the separator and returns Option<(&str, &str)>:

key=name value=Ada Lovelace

First occurrence only: "a=b=c".split_once('=') gives ("a", "b=c"), so a value that contains the separator survives. rsplit_once makes the same cut from the other end — "report.tar.gz".rsplit_once('.') gives ("report.tar", "gz") — and splitn(2, ':') yields at most two pieces, the second holding whatever is left.

One compile error waits for anyone who wants owned Strings out of split. The pieces are &str, and the compiler says so:

error[E0277]: a value of type `Vec<String>` cannot be built from an iterator over elements of type `&str`
--> src/main.rs:3:47
|
3 | let fields: Vec<String> = line.split(',').collect();
| ^^^^^^^ value of type `Vec<String>` cannot be built from `std::iter::Iterator<Item=&str>`
|
help: the trait `FromIterator<&str>` is not implemented for `Vec<String>`
but trait `FromIterator<String>` is implemented for it
--> /rustc/b940084d7eb6a299eb4bfeb8e34901bc051e7ac4/library/alloc/src/vec/mod.rs:3993:0
= help: for that trait implementation, expected `String`, found `&str`
note: the method call chain might not have had the expected associated types
--> src/main.rs:3:36
|
2 | let line = "alpha,beta,gamma";
| ------------------ this expression has type `&str`
3 | let fields: Vec<String> = line.split(',').collect();
| ^^^^^^^^^^ `Iterator::Item` is `&str` here
note: required by a bound in `collect`
--> /rustc/b940084d7eb6a299eb4bfeb8e34901bc051e7ac4/library/core/src/iter/traits/iterator.rs:2073:4
For more information about this error, try `rustc --explain E0277`.

Map the slices into owned strings first — .map(String::from).collect() — or keep the &str slices when borrowing is enough.