Strings and Text Processing

split() and split_whitespace()

str provides a rich family of zero-allocation splitting iterators that yield &str substrings borrowing directly from the source string without copying bytes onto the heap.

Reference of Splitting Methods on str

Method Delimiter / Rule Trailing Empty Behavior Returns
s.split(pat) char, &str, &[char], or FnMut(char) -> bool Preserves trailing "" after a final delimiter Iterator<Item = &str>
s.rsplit(pat) Same as split, scanned from the right Preserves leading "" Iterator<Item = &str>
s.split_terminator(pat) Same as split, treating trailing delimiter as a terminator Drops trailing "" after a final delimiter Iterator<Item = &str>
s.splitn(n, pat) Splits into at most n pieces (last piece contains the unsplit remainder) Preserves empty fields Iterator<Item = &str>
s.split_once(pat) Splits at the first delimiter into a 2-tuple Returns None if delimiter is absent Option<(&str, &str)>
s.rsplit_once(pat) Splits at the last delimiter into a 2-tuple Returns None if delimiter is absent Option<(&str, &str)>
s.split_whitespace() Splits on runs of any Unicode whitespace (char::is_whitespace) Skips leading, trailing, and consecutive whitespace Iterator<Item = &str>
s.split_ascii_whitespace() Splits on runs of ASCII whitespace (' ', '\t', '\n', '\r', '\x0C') Skips leading, trailing, and consecutive whitespace Iterator<Item = &str>

Comparing split(), split_terminator(), and split_whitespace()

"a,b,"
  ├── .split(',')            ──> ["a", "b", ""]   (3 items; trailing "" kept)
  └── .split_terminator(',') ──> ["a", "b"]       (2 items; trailing "" dropped)

"  hello   world \t\n "
  └── .split_whitespace()    ──> ["hello", "world"]
fn main() {
    let csv = "alpha,beta,";
    println!("split(','):            {:?}", csv.split(',').collect::<Vec<_>>());
    println!(
        "split_terminator(','): {:?}",
        csv.split_terminator(',').collect::<Vec<_>>()
    );

    let messy = "   rust\t\t2024\n  edition  ";
    let words: Vec<&str> = messy.split_whitespace().collect();
    println!("split_whitespace():    {words:?}");
}
split(','):            ["alpha", "beta", ""]
split_terminator(','): ["alpha", "beta"]
split_whitespace():    ["rust", "2024", "edition"]

Parsing Key-Value Pairs with split_once() and rsplit_once()

When splitting a string into exactly two parts (such as KEY=VALUE or filename.ext), prefer .split_once() and .rsplit_once() over .splitn(2, ...) because they return Option<(&str, &str)> directly without constructing an iterator:

fn main() {
    let header = "Authorization: Bearer secret:token";
    if let Some((name, value)) = header.split_once(": ") {
        println!("Header '{name}' = '{value}'");
    }

    let filename = "archive.tar.gz";
    if let Some((stem, ext)) = filename.rsplit_once('.') {
        println!("Stem: '{stem}', extension: '{ext}'");
    }
}
Header 'Authorization' = 'Bearer secret:token'
Stem: 'archive.tar', extension: 'gz'