Step 5 of 6
Changing case, searching, replacing and trimming
Here are the everyday tools for cleaning up and inspecting text, applied to a messy log line:
fn main() {
let line = " ERROR: Disk full on /dev/sda1 ";
let clean = line.trim();
println!("[{clean}]");
println!("{}", clean.to_lowercase());
println!("{}", clean.contains("Disk"));
println!("{}", clean.contains("disk"));
println!("{}", clean.replace("/dev/sda1", "drive 1"));
println!("[{line}]");
}
[ERROR: Disk full on /dev/sda1]
error: disk full on /dev/sda1
true
false
ERROR: Disk full on drive 1
[ ERROR: Disk full on /dev/sda1 ]
trim()removes whitespace (spaces, tabs, newlines) from both ends.trim_start()andtrim_end()do one side. You'll call it constantly in the next module, because every line a user types ends with a newline.to_uppercase()/to_lowercase()return a newStringwith the case changed. They handle non-English letters too:"straße".to_uppercase()is"STRASSE".contains(pattern)returnstrueif the pattern appears anywhere. It's case-sensitive:"Disk"is found,"disk"isn't.replace(from, to)returns a newStringwith every occurrence replaced. The pattern can also be achar:s.replace(' ', "_").
Look at the last line of output: none of these methods change the original. to_lowercase and replace build a new String; trim returns a &str view of the middle part (nothing is copied); contains just answers a question.
Chaining
Each method returns a value that has methods of its own, so you can chain them. Read the chain left to right:
fn main() {
let raw = " Hello World ";
let slug = raw.trim().to_lowercase().replace(' ', "-");
println!("{slug}");
let shouted = "is anyone there?".to_uppercase();
println!("{}", shouted.contains("ANYONE"));
}
hello-world
true
To search ignoring case, lowercase the text first and search for a lowercase pattern: line.to_lowercase().contains("error") finds ERROR, Error and error.
Common mistakes
- Expecting the original to change. This line computes an uppercase copy and throws it away:
name.to_uppercase(); // warning: unused return value of `str::<impl str>::to_uppercase` that must be used
The compiler warns you, and the note says: this returns the uppercase string as a new String, without modifying the original. Keep the result: let name = name.to_uppercase(); (shadowing works nicely here).
- Forgetting that
containsis case-sensitive."ERROR".contains("error")isfalse. - Mixing up the argument order of
replace: it'sreplace(what_to_find, what_to_put_instead).
Your task
Write normalize_tag(tag), which cleans up a tag typed by a user: remove spaces at the ends, make it lowercase, and replace each remaining space with -. For example normalize_tag(" Rust Lang ") returns "rust-lang".
Challenge 2
Write is_alert(line), which returns true when a log line mentions error or fatal, in any mix of upper and lower case.
Challenge 3
Write censor(text, word), which replaces every occurrence of word with stars, one * per character of the word. For example censor("darn it, darn", "darn") returns "**** it, ****", and censor("café café", "café") returns "**** ****".
Previous: Length: bytes versus characters Next: Comparing strings