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
&strvalues 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.
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.
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
| Method | What it does | Best use case |
|---|---|---|
split(delimiter) | Splits on every match of a pattern | General-purpose splitting |
split_once(delimiter) | Splits into two parts at the first match | Key/value pairs like a=b |
split_whitespace() | Splits on any amount of whitespace | User input, words in text |
lines() | Splits by line boundaries | Reading multiline text |
rsplit(delimiter) | Splits from the right | Parsing suffixes or file extensions |
split vs split_once
- Use
splitwhen you want many pieces. - Use
split_oncewhen you only expect two pieces.
let text = "a=b=c";
println!("{:?}", text.split('=').collect::<Vec<_>>());
println!("{:?}", text.split_once('='));
split(' ') vs split_whitespace()
| Approach | Behavior |
|---|---|
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
| Type | Ownership | Allocation |
|---|---|---|
&str | Borrowed from original text | Usually no new allocation |
String | Owns its own text | Usually 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.
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 aVec - split results are often
&strslices - delimiters can be a
charor&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();
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.
Keep learning
Related questions
Absolute Values in Rust: Using the abs() Method
Learn how to calculate absolute values in modern Rust with abs(), handle signed integer overflow, and choose safer alternatives.
Accepting Iterators in Rust Functions with impl Iterator
Learn how to write Rust functions that accept HashMap iterators using generic bounds or impl Iterator, avoiding trait object and lifetime errors.
Access Enum Variant Values in Rust with Pattern Matching
Learn how to extract and print values stored in Rust enum variants using match and if let pattern matching, with practical examples.