Как мне декодировать URL и получить строку запроса в виде HashMap?

У меня есть такой URL:

http%3A%2F%2Fexample.com%3Fa%3D1%26b%3D2%26c%3D3

Я разобрал это с hyper::Url::parse и получить строку запроса:

let parsed_url = hyper::Url::parse(&u).unwrap();
let query_string = parsed_url.query();

Но это дает мне запрос в виде строки. Я хочу получить строку запроса как HashMap, что-то вроде этого:

// some code to convert query string to HashMap
hash_query.get(&"a"); // eq to 1
hash_query.get(&"b"); // eq to 2

3 ответа

Решение

Есть несколько шагов:

  • .query_pairs() метод даст вам итератор по парам Cow<str>,

  • призвание .into_owned() на что даст вам итератор String пары вместо

  • Это итератор (String, String), которая является точно правильной формы .collect() в HashMap<String, String>,

Собираем это вместе:

let parsed_url = Url::parse("http://example.com/?a=1&b=2&c=3").unwrap();
let hash_query: HashMap<_, _> = parsed_url.query_pairs().into_owned().collect();
assert_eq!(hash_query.get("a"), "1");

Обратите внимание, что вам нужна аннотация типа на hash_query -поскольку .collect() перегружен, вы должны указать компилятору, какой тип коллекции вы хотите.

Другой ответ хорош, но я считаю, что это должно быть проще, поэтому я заключил его в функцию:

      use {
   std::collections::HashMap,
   url::Url
};

fn query(u: Url) -> HashMap<String, String> {
   u.query_pairs().into_owned().collect()
}

fn main() -> Result<(), url::ParseError> {
   let u = Url::parse("http://stackoverflow.com?month=May&day=Friday")?;
   let q = query(u);
   println!("{:?}", q);
   Ok(())
}

В качестве альтернативы я нашел другой ящик, который сделает это за вас:

      use auris::URI;

fn main() -> Result<(), auris::ParseError> {
   let s = "http://stackoverflow.com?month=May&day=Friday";
   let u: URI<String> = s.parse()?;
   println!("{:?}", u.qs); // Some({"month": "May", "day": "Friday"})
   Ok(())
}

https://docs.rs/auris

Вот решение для разбора уже декодированной строки запроса из&strвHashMap<String, String>используя только стандартную библиотеку Rust, без необходимости использования внешних крейтов:

      use std::collections::HashMap;

fn parse_query(query: &str) -> HashMap<String, String> {
    query
        .split('&')
        .filter_map(|s| {
            s.split_once('=')
                .and_then(|t| Some((t.0.to_owned(), t.1.to_owned())))
        })
        .collect()
}
Другие вопросы по тегам