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 becomeband the lastahas 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, becauseCandcare 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:
- Below the existing
sentencevariable, declareresultwithlet. - 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 newString.- The original is not changed, so store the result.
replacen(from, to, count)limits how many matches change.- The pattern can be a
&str, acharor an array of chars, and the replacement is a&str. - Matching is case-sensitive and never overlaps.
