Простой способ разобрать URL в C ++ кроссплатформенном? - PullRequest
64 голосов
/ 11 апреля 2010

Мне нужно проанализировать URL-адрес, чтобы получить протокол, хост, путь и запрос в приложении, которое я пишу на C ++. Приложение предназначено для кроссплатформенности. Я удивлен, что не могу найти ничего, что делает это в библиотеках boost или POCO . Это где-то очевидно, что я не смотрю? Любые предложения по соответствующим библиотекам с открытым исходным кодом? Или это то, что я должен сделать сам? Это не супер сложно, но кажется, что это обычная задача, и я удивлен, что нет единого решения.

Ответы [ 17 ]

1 голос
/ 06 января 2011

Существует недавно выпущенная библиотека Google-URL:

http://code.google.com/p/google-url/

Библиотека предоставляет API-интерфейс для низкоуровневого анализа URL-адресов, а также высокоуровневую абстракцию под названием GURL. Вот пример использования этого:

#include <googleurl\src\gurl.h>

wchar_t url[] = L"http://www.facebook.com";
GURL parsedUrl (url);
assert(parsedUrl.DomainIs("facebook.com"));

У меня есть две небольшие жалобы: (1) он хочет использовать ICU по умолчанию для работы с различными кодировками строк и (2) он делает некоторые предположения о ведении журнала (но я думаю, что они могут быть отключены). Другими словами, библиотека не является полностью автономной, поскольку она существует, но я думаю, что она все еще является хорошей основой для начала, особенно если вы уже используете ICU.

1 голос
/ 30 сентября 2016

Вы можете попробовать библиотеку с открытым исходным кодом C ++ REST SDK (созданную Microsoft, распространяемую по лицензии Apache License 2.0). Он может быть построен для нескольких платформ, включая Windows, Linux, OSX, iOS, Android). Существует класс с именем web::uri, в который вы помещаете строку и можете получать отдельные компоненты URL. Вот пример кода (проверено на Windows):

#include <cpprest/base_uri.h>
#include <iostream>
#include <ostream>

web::uri sample_uri( L"http://dummyuser@localhost:7777/dummypath?dummyquery#dummyfragment" );
std::wcout << L"scheme: "   << sample_uri.scheme()     << std::endl;
std::wcout << L"user: "     << sample_uri.user_info()  << std::endl;
std::wcout << L"host: "     << sample_uri.host()       << std::endl;
std::wcout << L"port: "     << sample_uri.port()       << std::endl;
std::wcout << L"path: "     << sample_uri.path()       << std::endl;
std::wcout << L"query: "    << sample_uri.query()      << std::endl;
std::wcout << L"fragment: " << sample_uri.fragment()   << std::endl;

Вывод будет:

scheme: http
user: dummyuser
host: localhost
port: 7777
path: /dummypath
query: dummyquery
fragment: dummyfragment

Существуют и другие простые в использовании методы, например, чтобы получить доступ к отдельным парам атрибут / значение из запроса, разбить путь на компоненты и т. д.

1 голос
/ 20 марта 2019

Небольшая зависимость, которую вы можете использовать: uriparser , которая недавно была перемещена в GitHub

Вы можете найти минимальный пример в их коде: https://github.com/uriparser/uriparser/blob/63384be4fb8197264c55ff53a135110ecd5bd8c4/tool/uriparse.c

Это будет легче, чем Boost или Poco. Единственная загвоздка в том, что это C.

Существует также Buckaroo пакет:

buckaroo add github.com/buckaroo-pm/uriparser
1 голос
/ 11 апреля 2010

QT имеет QUrl для этого. В GNOME есть SoupURI в libsoup , который вы, вероятно, найдете немного более легким.

1 голос
/ 28 ноября 2018

Могу ли я предложить другое автономное решение на основе std :: regex:

const char* SCHEME_REGEX   = "((http[s]?)://)?";  // match http or https before the ://
const char* USER_REGEX     = "(([^@/:\\s]+)@)?";  // match anything other than @ / : or whitespace before the ending @
const char* HOST_REGEX     = "([^@/:\\s]+)";      // mandatory. match anything other than @ / : or whitespace
const char* PORT_REGEX     = "(:([0-9]{1,5}))?";  // after the : match 1 to 5 digits
const char* PATH_REGEX     = "(/[^:#?\\s]*)?";    // after the / match anything other than : # ? or whitespace
const char* QUERY_REGEX    = "(\\?(([^?;&#=]+=[^?;&#=]+)([;|&]([^?;&#=]+=[^?;&#=]+))*))?"; // after the ? match any number of x=y pairs, seperated by & or ;
const char* FRAGMENT_REGEX = "(#([^#\\s]*))?";    // after the # match anything other than # or whitespace

bool parseUri(const std::string &i_uri)
{
    static const std::regex regExpr(std::string("^")
        + SCHEME_REGEX + USER_REGEX
        + HOST_REGEX + PORT_REGEX
        + PATH_REGEX + QUERY_REGEX
        + FRAGMENT_REGEX + "$");

    std::smatch matchResults;
    if (std::regex_match(i_uri.cbegin(), i_uri.cend(), matchResults, regExpr))
    {
        m_scheme.assign(matchResults[2].first, matchResults[2].second);
        m_user.assign(matchResults[4].first, matchResults[4].second);
        m_host.assign(matchResults[5].first, matchResults[5].second);
        m_port.assign(matchResults[7].first, matchResults[7].second);
        m_path.assign(matchResults[8].first, matchResults[8].second);
        m_query.assign(matchResults[10].first, matchResults[10].second);
        m_fragment.assign(matchResults[15].first, matchResults[15].second);

        return true;
    }

    return false;
}

Я добавил пояснения для каждой части регулярного выражения. Этот способ позволяет вам выбрать именно те части, которые нужно проанализировать для URL, который вы ожидаете получить. Просто не забудьте изменить нужные индексы группы регулярных выражений соответственно.

0 голосов
/ 10 декабря 2018

Я разработал «объектно-ориентированное» решение, один класс C ++, который работает с одним регулярным выражением, таким как решения @ Mr.Jones и @velcrow. Мой класс Url выполняет разбор URL / uri.

Я думаю, что улучшил Velcrow регулярное выражение, чтобы быть более устойчивым и включает также часть имени пользователя.

Следуя первой версии моей идеи, я выпустил тот же код, улучшенный, в моем GPL3 лицензированном проекте с открытым исходным кодом Cpp URL Parser .

Пропущено #ifdef/ndef раздутая часть, следует Url.h

#include <string>
#include <iostream>
#include <boost/regex.hpp>

using namespace std;

class Url {
public:
    boost::regex ex;
    string rawUrl;

    string username;
    string protocol;
    string domain;
    string port;
    string path;
    string query;
    string fragment;

    Url();

    Url(string &rawUrl);

    Url &update(string &rawUrl);
};

Это код файла реализации Url.cpp:

#include "Url.h"

Url::Url() {
    this -> ex = boost::regex("(ssh|sftp|ftp|smb|http|https):\\/\\/(?:([^@ ]*)@)?([^:?# ]+)(?::(\\d+))?([^?# ]*)(?:\\?([^# ]*))?(?:#([^ ]*))?");
}

Url::Url(string &rawUrl) : Url() {
    this->rawUrl = rawUrl;
    this->update(this->rawUrl);
}

Url &Url::update(string &rawUrl) {
    this->rawUrl = rawUrl;
    boost::cmatch what;
    if (regex_match(rawUrl.c_str(), what, ex)) {
        this -> protocol = string(what[1].first, what[1].second);
        this -> username = string(what[2].first, what[2].second);
        this -> domain = string(what[3].first, what[3].second);
        this -> port = string(what[4].first, what[4].second);
        this -> path = string(what[5].first, what[5].second);
        this -> query = string(what[6].first, what[6].second);
        this -> fragment = string(what[7].first, what[7].second);
    }
    return *this;
}

Пример использования:

string urlString = "http://gino@ciao.it:67/ciao?roba=ciao#34";
Url *url = new Url(urlString);
std::cout << " username: " << url->username << " URL domain: " << url->domain;
std::cout << " port: " << url->port << " protocol: " << url->protocol;

Вы также можете обновить объект Url, чтобы представлять (и анализировать) другой URL:

url.update("http://gino@nuovociao.it:68/nuovociao?roba=ciaoooo#")

Я только сейчас изучаю C ++, так что я не уверен, что следовал 100% рекомендациям C ++. Любой совет приветствуется.

P.s: давайте посмотрим на Cpp URL Parser , там есть уточнения.

Веселись

0 голосов
/ 20 декабря 2017

Существует еще одна библиотека https://snapwebsites.org/project/libtld, которая обрабатывает все возможные домены верхнего уровня и схему URI

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...