How to decode URL-encoded and URL query strings in Rust

2 Answers

0 votes
use percent_encoding::percent_decode_str;

/// Decodes a URL-encoded string.
/// Replaces '+' with spaces and decodes percent-encoded characters (%xx).
fn decode_url_string(encoded_str: &str) -> String {
    // Fixed: changed 'encodedStr' to 'encoded_str' to match the parameter name
    let normalized = encoded_str.replace('+', " ");
    
    // Decode percent-encoded sequences, returning a Cow<str> which we convert to String
    percent_decode_str(&normalized)
        .decode_utf8_lossy()
        .into_owned()
}

fn main() {
    // Example 1: Standard URL encoding with special characters
    let sample1 = "Hello%20World%21%20Rust%20%26%20Web";
    println!("--- Example 1: Standard URL Encoding ---");
    println!("Encoded: {}", sample1);
    println!("Decoded: {}", decode_url_string(sample1));

    // Example 2: Form query string fragment encoding (spaces as '+')
    let sample2 = "Jane+Doe+from+New+York";
    println!("\n--- Example 2: Form Fragment Encoding ---");
    println!("Encoded: {}", sample2);
    println!("Decoded: {}", decode_url_string(sample2));
}


/*
run:

--- Example 1: Standard URL Encoding ---
Encoded: Hello%20World%21%20Rust%20%26%20Web
Decoded: Hello World! Rust & Web

--- Example 2: Form Fragment Encoding ---
Encoded: Jane+Doe+from+New+York
Decoded: Jane Doe from New York

*/

 



answered 1 hour ago by avibootz
0 votes
use std::collections::HashMap;
use url::form_urlencoded;

/// Parses and decodes a complete URL query string into a HashMap.
/// Handles multi-value parameters by grouping them into a vector.
fn parse_and_decode_query(query_string: &str) -> HashMap<String, Vec<String>> {
    // Remove leading '?' if present
    let clean_query = query_string.strip_prefix('?').unwrap_or(query_string);
    
    let mut result: HashMap<String, Vec<String>> = HashMap::new();

    // form_urlencoded::parse parses and decodes keys and values automatically
    for (key, value) in form_urlencoded::parse(clean_query.as_bytes()) {
        result.entry(key.into_owned())
            .or_default()
            .push(value.into_owned());
    }

    result
}

fn main() {
    let full_query = "search=rust+tutorial&category=programming&tag=beginner&tag=async";

    println!("--- Full Query String Parsing ---");
    println!("Original Query: {}", full_query);

    let decoded_map = parse_and_decode_query(full_query);

    println!("Decoded Map Result:");
    for (key, values) in &decoded_map {
        println!("  {} -> {:?}", key, values);
    }
}


/*
run:

--- Full Query String Parsing ---
Original Query: search=rust+tutorial&category=programming&tag=beginner&tag=async
Decoded Map Result:
  tag -> ["beginner", "async"]
  search -> ["rust tutorial"]
  category -> ["programming"]

*/

 



answered 1 hour ago by avibootz
...