I know there is an API for this but in order to help myself understand Rust more, I've written my own URL decoder. I've done it in two different ways. Both work but I wonder if there is a neater way in some iterator feature I've not met yet or which one you might prefer to use because of reasons I don't know yet when writing things like this. I'm using two different ways to iterate over the characters in a string and build up a new one based on it. One uses a filter_map and the other a for loop.
I found it interesting I could make a closure change data outside the closure!
What do you think?
fn main() {
let url =
"https%3A%2F%2Fdoc.rust-lang.org%2Fstd%2Fiter%2Ftrait.Iterator.html%23method.try_reduce"
.to_string();
println!("{}", decode_url1(&url));
println!("{}", decode_url2(&url));
}
fn decode_url2(url: &str) -> String {
let mut is_hex = false;
let mut hex_char = String::new();
let url_decode = |c| {
if c == '%' {
hex_char.clear();
is_hex = true;
None
} else if is_hex {
hex_char.push(c);
if hex_char.len() == 2 {
is_hex = false;
Some(hex_to_char(&hex_char))
} else {
None
}
} else {
Some(c)
}
};
url.chars().filter_map(url_decode).collect()
}
fn decode_url1(url: &str) -> String {
let mut ret = String::with_capacity(url.len());
let mut is_hex = false;
let mut hex_char = String::new();
for c in url.chars() {
if c == '%' {
hex_char.clear();
is_hex = true;
} else if is_hex {
hex_char.push(c);
if hex_char.len() == 2 {
is_hex = false;
ret.push(hex_to_char(&hex_char))
}
} else {
ret.push(c);
}
}
ret
}
fn hex_to_char(s: &str) -> char {
char::from((u8::from_str_radix(s, 16)).unwrap())
}