Start learning free

LESSON 67 OF 414 · STRINGS I

String Replace in Rust: Using str::replace

Lesson Read the full explanation

In Rust, the .replace() method replaces every occurrence of a substring with a new string. It takes the substring to find and the replacement directly:

let result = sentence.replace("cats", "dogs");
// .replace() takes the substring to find
// "dogs" is the replacement

Here is an example:

let sentence = "I love cats";
let result = sentence.replace("cats", "dogs");
println!("{}", result);  // I love dogs

Assignment
Follow the Coding Tutorial and replace "cats" with "dogs" in sentence!


Hint
Use sentence.replace("cats", "dogs") and assign the result to result.

STEP 1 OF 1
    Ctrl + Enter to check

    RUST · STRINGS I

    String Replace in Rust, explained

    What replace does

    The replace method finds every occurrence of a piece of text inside a string and swaps it for another piece of text. It takes two arguments: the text to find and the text to put in its place.

    let sentence = "I love cats";
    let result = sentence.replace("cats", "dogs");
    println!("{}", result);
    
    I love dogs
    

    The method is defined on str, so it works on string literals (&str) and on String values alike.

    It returns a new String

    Strings can't be edited in place through a &str, and replace never tries. It builds a new String with the changes and leaves the original untouched:

    let sentence = "I love cats and cats";
    let result = sentence.replace("cats", "dogs");
    println!("{}", result);
    println!("{}", sentence);
    
    I love dogs and dogs
    I love cats and cats
    

    Calling sentence.replace("cats", "dogs") and ignoring the return value therefore achieves nothing. The new text exists only if you store it, as the lesson does with result. Note the types too: sentence is a &str, while result is an owned String.

    Every match is replaced

    As the example shows, both occurrences of "cats" changed. To replace only the first few matches, use replacen, which takes a count as its last argument:

    let sentence = "I love cats and cats";
    println!("{}", sentence.replacen("cats", "dogs", 1));
    
    I love dogs and cats
    

    What can be searched for

    The first argument is a pattern. A string slice is the most common choice, but a single char works too, and so does an array of chars, which matches any of them:

    println!("{}", "hello".replace('l', "L"));
    println!("{}", "a-b_c".replace(['-', '_'], " "));
    
    heLLo
    a b c
    

    The replacement is always a string slice, even when the pattern is a char. Writing replace('l', 'L') is a type error, because the second argument must be a &str.

    Replacing in a String you own

    The method works the same on a String. The usual way to update a variable with the replaced text is to assign the result back, which needs the variable to be mut:

    let mut text = String::from("I love cats");
    text = text.replace("cats", "dogs");
    println!("{}", text);
    
    I love dogs
    

    The old string is dropped when the new one is assigned.

    Gotchas

    • Matches don't overlap. The search moves left to right, and each match uses up its characters. "aaa".replace("aa", "b") gives "ba": the first two letters become b and the last a has no partner.
    • Replaced text isn't searched again. The replacement is added to the output, and the search continues after the match in the original string, so a replacement that contains the pattern can't loop.
    • The search is case-sensitive. "Cats".replace("cats", "dogs") changes nothing, because C and c are different characters.
    • An empty pattern matches everywhere. "abc".replace("", "-") gives "-a-b-c-": the empty string matches before every character and at the end.
    • No match is fine. If the pattern doesn't occur, you get a copy of the original text. No error, no Option.

    Replacing and removing

    Replacing with an empty string deletes the matches. "1,234,567".replace(",", "") is "1234567". Chaining calls applies several replacements in turn, since each call returns a String that you can call replace on again:

    let tidy = "a-b_c".replace("-", " ").replace("_", " ");
    println!("{}", tidy);
    
    a b c
    

    Chaining is fine for a handful of replacements. Keep the order in mind, because a later call sees the output of the earlier ones.

    Replacing in place is also possible when you own a String. replace_range overwrites a byte range of a mut String, but it needs exact positions, so for "change every occurrence of this text" replace is simpler.

    The exercise

    The lesson gives you sentence holding "I love cats" and asks for "cats" to become "dogs". It is one step:

    1. Below the existing sentence variable, declare result with let.
    2. Assign it sentence.replace("cats", "dogs").
            let sentence = "I love cats";
    
            let result = sentence.replace("cats", "dogs");
    

    The new variable is a separate String, so sentence still reads "I love cats" afterwards. There is no mut anywhere, because nothing is modified. If you do want to update a variable with its own replaced text, write let text = text.replace(...) to shadow it, or declare it mut and assign to it.

    Key takeaways

    • text.replace(from, to) replaces every match and returns a new String.
    • The original is not changed, so store the result.
    • replacen(from, to, count) limits how many matches change.
    • The pattern can be a &str, a char or an array of chars, and the replacement is a &str.
    • Matching is case-sensitive and never overlaps.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free