Rust String Methods
String methods are the everyday tools for splitting, trimming, searching, and building text. A String is owned text, and &str is a borrowed view of text.
Cut text into pieces with split
split cuts at every comma and gives the pieces one by one. collect gathers them into a Vec:
let parts: Vec<&str> = "ada,36,london".split(',').collect();
println!("{:?}", parts);Trim the ends, test the middle
trim removes spaces from both ends. contains tests whether a piece of text appears inside:
let raw = " hello rust ";
println!("[{}]", raw.trim());
println!("has rust = {}", raw.contains("rust"));Swap pieces with replace
replace builds a new String with every match swapped. The original text is untouched:
let fixed = "I like cats".replace("cats", "crabs");
println!("{fixed}");Walk lines, then letters
lines() hands you one line at a time. chars() walks the letters — "héllo" has five of them, however many bytes they take:
for line in "one\ntwo".lines() {
println!("line: {line}");
}
println!("letters = {}", "héllo".chars().count());Slice text at a letter edge
A range cuts by bytes, and both ends must sit on letter edges. Here 0..4 takes h, é (two bytes) and the first l:
let hello = "héllo";
println!("{}", &hello[0..4]);One letter a reader sees can be several chars
A flag looks like one letter, but it is a pair of regional symbols — two chars. And é can be written as e plus a combining accent: two chars that print as one letter. Bytes, chars and reader-letters are three different counts:
println!("flag: {} bytes, {} chars", "🇬🇧".len(), "🇬🇧".chars().count());
println!("e + accent: {} bytes, {} chars", "e\u{301}".len(), "e\u{301}".chars().count());Example
fn main() {
let csv = "ada,36,london";
let parts: Vec<&str> = csv.split(',').collect();
let shouted = parts[0].to_uppercase();
let bytes = "héllo".len();
let chars = "héllo".chars().count();
println!("{:?} {} bytes={} chars={}", parts, shouted, bytes, chars);
}Key points
- Every method in this lesson works on text as Rust stores it: UTF-8 bytes grouped into letters.
- Cutting text by position only works at a letter edge.
- Cutting in the middle of a multi-byte letter stops the program.
- Text has three views.
- Bytes are the raw numbers.
- Chars are Unicode scalar values.
- Grapheme clusters are what a reader calls letters.
- Rust gives bytes() and chars() directly.
- Graphemes need an extra crate.
- There is no s[i] for one letter: use s.chars().nth(i) to get the i-th character as an Option — characters are counted, not bytes
- Use s.char_indices() to walk the text as (byte position, char) pairs, and s.is_char_boundary(i) to ask whether byte position i is safe to cut at
In this example, csv holds one line of comma-separated text. split(',') cuts it into three pieces, and collect() gathers them into a Vec: "ada", "36", "london". to_uppercase() builds a new String, "ADA", from the first piece. The split pieces are borrowed views of the original text — no copying happened. Finally, "héllo" shows the byte/letter difference: .len() counts 6 bytes, .chars().count() counts 5 letters.
Note
"héllo" has 5 chars but 6 bytes, because é takes two bytes.
This is why Rust offers chars() and bytes() as separate tools.
Other languages often blur this difference until it causes a bug.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Rust Playground
Exercise
Why can't you index a String with s[0] in Rust?