🎓 A1Learner
🔍

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?