Question

How to Split a String in Rust

Question

In Rust, how can I split a string into parts using a delimiter?

For example, in Java you might write:

"some string 123 ffd".split("123");

What is the Rust equivalent, and how does string splitting work in Rust?

Short Answer

By the end of this page, you will understand how to split strings in Rust using .split(), what kind of values it returns, how to collect the results, and how to use common related methods such as split_once, split_whitespace, and lines in practical code.

Concept

Rust provides string-splitting methods on str, the string slice type. The most common one is .split(...), which separates a string wherever a given pattern appears.

For example:

let text = "some string 123 ffd";
let parts: Vec<&str> = text.split("123").collect();

This produces pieces of the original string without copying the text. That is an important Rust idea:

  • split() returns an iterator
  • each item is usually a &str
  • those &str values are slices pointing into the original string

This matters because Rust tries to avoid unnecessary memory allocation. Instead of creating brand new strings immediately, it gives you borrowed views into the original string.

You can then:

  • loop through the pieces
  • collect them into a Vec<&str>
  • take only the first few pieces
  • parse the pieces into other types

String splitting is common in real programming because text data often comes in structured forms such as:

  • CSV-like input
  • log lines
  • URLs
  • configuration files
  • command-line input
  • API responses

Understanding Rust string splitting also helps you understand two core Rust ideas:

  • iterators for processing sequences lazily
  • borrowing because the split parts reference the original string

Mental Model

Think of a string as a long strip of paper.

When you use split(), Rust does not immediately make brand new strips of paper. Instead, it marks the positions where the delimiter appears and gives you views of each section.

So if the string is:

some string 123 ffd

and the delimiter is 123, Rust sees:

[some string ][ ffd]

The results are slices into the original text, like pointing at sections of the same paper rather than photocopying them.

This is why splitting is efficient in Rust: you usually borrow pieces first, and only create owned String values if you actually need them.

Take Quiz

Syntax and Examples

Basic syntax

let text = "some string 123 ffd";
let parts = text.split("123");

parts is an iterator, not a vector yet.

Collecting into a vector

let text = "some string 123 ffd";
let parts: Vec<&str> = text.split("123").collect();

println!("{:?}", parts);

Output:

["some string ", " ffd"]

Splitting by a single character

let csv = "red,green,blue";
let colors: Vec<&str> = csv.split(',').collect();

println!("{:?}", colors);

Output:

["red", "green", "blue"]

Iterating without collecting

let text = "apple|banana|orange";

for part in text.split('|') {
    println!("{}", part);
}

This is useful when you only need to process items one by one.

Using split_once for exactly two parts

let entry = "name=alice";

if let Some((key, value)) = entry.split_once('=') {
    println!("key: {}", key);
    println!("value: {}", value);
}

This is often cleaner when you only want the first split.

Splitting on whitespace

let sentence = "Rust   is fast and safe";
let words: Vec<&str> = sentence.split_whitespace().collect();

println!("{:?}", words);

Output:

["Rust", "is", "fast", "and", "safe"]

Unlike split(' '), split_whitespace() handles multiple spaces neatly.

Step by Step Execution

Consider this example:

let text = "some string 123 ffd";
let parts: Vec<&str> = text.split("123").collect();
println!("{:?}", parts);

Step 1: Create the string slice

let text = "some string 123 ffd";

text is a &str, a borrowed string slice.

Step 2: Call split

text.split("123")

Rust searches for every occurrence of "123" in the string.

It finds this structure:

  • before 123: "some string "
  • after 123: " ffd"

At this point, Rust creates an iterator over those pieces.

Step 3: Collect the iterator

let parts: Vec<&str> = text.split("123").collect();

collect() consumes the iterator and stores the results in a vector.

Now parts contains:

["some string ", " ffd"]

Step 4: Print the result

println!("{:?}", parts);

This prints the vector in debug format.

Another traceable example

let data = "a-b-c";
let mut iter = data.split('-');

println!("{:?}", iter.next());
println!("{:?}", iter.next());
println!("{:?}", iter.next());
println!("{:?}", iter.next());

Output:

Some("a")
Some("b")
Some("c")
None

This shows that split() returns items one at a time through an iterator.

Real World Use Cases

Parsing configuration values

let line = "host=localhost";
if let Some((key, value)) = line.split_once('=') {
    println!("{} -> {}", key, value);
}

Useful for simple .env-style or config files.

Reading CSV-like data

let row = "alice,30,developer";
let fields: Vec<&str> = row.split(',').collect();

Useful when reading simple comma-separated records.

Processing log lines

let log = "INFO: Server started";
if let Some((level, message)) = log.split_once(':') {
    println!("level={} message={}", level.trim(), message.trim());
}

Useful for log parsing and monitoring scripts.

Splitting URL or path segments

let path = "/users/42/profile";
let segments: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();

Useful in web servers and routing logic.

Tokenizing user input

let input = "add   milk bread eggs";
let items: Vec<&str> = input.split_whitespace().collect();

Useful for CLI tools and simple text commands.

Take Quiz

Real Codebase Usage

In real Rust projects, developers usually combine string splitting with iterator methods and validation.

Common patterns

Guard clauses with split_once

fn parse_pair(line: &str) {
    let Some((key, value)) = line.split_once('=') else {
        println!("Invalid input");
        return;
    };

    println!("{} = {}", key, value);
}

This avoids nested if statements and handles invalid input early.

Trimming after splitting

let line = "name = alice";
if let Some((key, value)) = line.split_once('=') {
    let key = key.trim();
    let value = value.trim();
    println!("{} -> {}", key, value);
}

Very common when parsing human-written text.

Filtering out empty parts

let path = "/api//users/";
let parts: Vec<&str> = path.split('/').filter(|p| !p.is_empty()).collect();

Useful because repeated delimiters often produce empty strings.

Parsing values after splitting

let point = "10,20";
if let Some((x, y)) = point.split_once(',') {
    let x: i32 = x.parse().unwrap();
    let y: i32 = y.parse().unwrap();
    println!("({}, {})", x, y);
}

This is common in input parsing and data transformation.

Keeping code lazy with iterators

let text = "a,b,c,d,e";
for item in text.split(',').take(2) {
    println!("{}", item);
}

This avoids collecting everything when you only need part of the result.

Common Mistakes

Mistake 1: Expecting split() to return a vector directly

Broken idea:

let parts = "a,b,c".split(',');
println!("{:?}", parts);

Why it is a problem:

  • split() returns an iterator
  • the iterator itself is not the final list of parts you may expect

Fix:

let parts: Vec<&str> = "a,b,c".split(',').collect();
println!("{:?}", parts);

Mistake 2: Using split(' ') when whitespace may vary

Broken code:

let text = "Rust   is great";
let parts: Vec<&str> = text.split(' ').collect();
println!("{:?}", parts);

Possible output:

["Rust", "", "", "is", "great"]

Fix:

let parts: Vec<&str> = text.split_whitespace().collect();

Mistake 3: Forgetting about empty strings

let text = ",a,b,";
let parts: Vec<&str> = text.split(',').collect();
println!("{:?}", parts);

Output:

["", "a", "b", ""]

If you do not want empty values:

let parts: Vec<&str> = text.split(',').filter(|s| !s.is_empty()).collect();

Mistake 4: Assuming split_once() always succeeds

Broken code:

let (key, value) = "hello".split_once('=').unwrap();

This will panic if = is not found.

Safer version:

if let Some((key, value)) = "hello".split_once('=') {
    println!("{} {}", key, value);
} else {
    println!("Delimiter not found");
}

Mistake 5: Confusing String and &str

split() usually gives &str slices.

If you need owned strings, convert them:

let owned_parts: Vec<String> = "a,b,c"
    .split(',')
    .map(String::from)
    .collect();

Comparisons

MethodWhat it doesBest use case
split(delimiter)Splits on every match of a patternGeneral-purpose splitting
split_once(delimiter)Splits into two parts at the first matchKey/value pairs like a=b
split_whitespace()Splits on any amount of whitespaceUser input, words in text
lines()Splits by line boundariesReading multiline text
rsplit(delimiter)Splits from the rightParsing suffixes or file extensions

split vs split_once

  • Use split when you want many pieces.
  • Use split_once when you only expect two pieces.
let text = "a=b=c";
println!("{:?}", text.split('=').collect::<Vec<_>>());
println!("{:?}", text.split_once('='));

split(' ') vs split_whitespace()

ApproachBehavior
split(' ')Splits only on the space character and may produce empty strings
split_whitespace()Handles multiple spaces, tabs, and newlines cleanly

&str slices vs owned String values

TypeOwnershipAllocation
&strBorrowed from original textUsually no new allocation
StringOwns its own textUsually allocates new memory

Choose &str when you only need to read the split parts. Choose String when you need to store or modify them independently.

Take Quiz

Cheat Sheet

// Split into many parts
let parts: Vec<&str> = "a,b,c".split(',').collect();

// Split using a string delimiter
let parts: Vec<&str> = "one--two--three".split("--").collect();

// Split into two parts only
let pair = "key=value".split_once('=');

// Split on whitespace
let words: Vec<&str> = "a   b\tc".split_whitespace().collect();

// Split into lines
let lines: Vec<&str> = "a\nb\nc".lines().collect();

// Remove empty parts
let parts: Vec<&str> = "/a//b/".split('/').filter(|s| !s.is_empty()).collect();

// Convert to owned strings
let owned: Vec<String> = "a,b,c".split(',').map(String::from).collect();

Rules to remember

  • split() returns an iterator
  • call .collect() if you want a Vec
  • split results are often &str slices
  • delimiters can be a char or &str
  • empty parts may appear if delimiters are repeated or at the edges
  • use split_whitespace() for flexible whitespace handling
  • use split_once() when only two parts are expected

FAQ

How do I split a string by a word in Rust?

Use .split("word"):

let parts: Vec<&str> = "abcWORDxyz".split("WORD").collect();

Does Rust split() return a Vec?

No. It returns an iterator. Use .collect() to turn it into a Vec.

How do I split a string only once in Rust?

Use .split_once(delimiter). It returns Option<(&str, &str)>.

How do I split by spaces in Rust?

You can use .split(' '), but .split_whitespace() is usually better because it handles multiple spaces, tabs, and newlines.

Why are the split results &str instead of String?

Because Rust borrows slices from the original string to avoid unnecessary allocations.

How do I remove empty strings after splitting?

Use .filter(|s| !s.is_empty()) after split().

Can I split a Rust String too?

Yes. String can be used as &str:

let s = String::from("a,b,c");
let parts: Vec<&str> = s.split(',').collect();
Take Quiz

Mini Project

Description

Build a small Rust parser for simple key=value configuration lines. This project demonstrates string splitting in a realistic format that appears in environment files, settings files, and command-line tools.

Goal

Create a program that reads several key=value lines, splits each line safely, trims whitespace, skips invalid lines, and prints the parsed key-value pairs.

Requirements

  • Store a few sample configuration lines in a collection.
  • For each line, split only once on the = character.
  • Trim whitespace around both the key and value.
  • Skip lines that do not contain =.
  • Print each valid key-value pair in a clear format.
Take Quiz

Keep learning

Related questions

View more