Łatwy sposób na analizę adresu url w C++ cross platform?

Muszę przeanalizować adres URL, aby uzyskać protokół, host, ścieżkę i zapytanie w aplikacji, którą piszę w C++. Aplikacja ma być wieloplatformowa. Dziwi mnie, że nie mogę znaleźć niczego, co by to robiło w bibliotekach boostlub POCO. Czy to oczywiste, że nie patrzę? Jakieś sugestie dotyczące odpowiednich bibliotek open source? Czy to jest coś, co muszę zrobić sam? To nie jest zbyt skomplikowane, ale wydaje się, że takie wspólne zadanie jestem zaskoczony, że nie ma wspólne rozwiązanie.

 58
Author: Elliot Cameron, 2010-04-11

14 answers

Istnieje biblioteka, która jest proponowana do włączenia Boost i pozwala łatwo analizować URI HTTP. Wykorzystuje Boost.Spirit i jest również wydany na licencji Boost Software. Biblioteką jest cpp-netlib, którego dokumentację można znaleźć pod adresem http://cpp-netlib.github.com / -- możesz pobrać najnowszą wersję z http://github.com/cpp-netlib/cpp-netlib/downloads .

Odpowiedni typ, którego chcesz użyć, to {[0] } i jest udokumentowany tutaj .

 27
Author: Dean Michael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-17 17:41:55

Strasznie przepraszam, nic na to nie poradzę. : s

Url.hh

#ifndef URL_HH_
#define URL_HH_    
#include <string>
struct url {
    url(const std::string& url_s); // omitted copy, ==, accessors, ...
private:
    void parse(const std::string& url_s);
private:
    std::string protocol_, host_, path_, query_;
};
#endif /* URL_HH_ */

Url.cc

#include "url.hh"
#include <string>
#include <algorithm>
#include <cctype>
#include <functional>
using namespace std;

// ctors, copy, equality, ...

void url::parse(const string& url_s)
{
    const string prot_end("://");
    string::const_iterator prot_i = search(url_s.begin(), url_s.end(),
                                           prot_end.begin(), prot_end.end());
    protocol_.reserve(distance(url_s.begin(), prot_i));
    transform(url_s.begin(), prot_i,
              back_inserter(protocol_),
              ptr_fun<int,int>(tolower)); // protocol is icase
    if( prot_i == url_s.end() )
        return;
    advance(prot_i, prot_end.length());
    string::const_iterator path_i = find(prot_i, url_s.end(), '/');
    host_.reserve(distance(prot_i, path_i));
    transform(prot_i, path_i,
              back_inserter(host_),
              ptr_fun<int,int>(tolower)); // host is icase
    string::const_iterator query_i = find(path_i, url_s.end(), '?');
    path_.assign(path_i, query_i);
    if( query_i != url_s.end() )
        ++query_i;
    query_.assign(query_i, url_s.end());
}

Main.cc

// ...
    url u("HTTP://stackoverflow.com/questions/2616011/parse-a.py?url=1");
    cout << u.protocol() << '\t' << u.host() << ...
 18
Author: wilhelmtell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-11 06:49:04

Wstring Wersja powyżej, dodano inne pola potrzebne. Może być dopracowany, ale wystarczająco dobry dla moich celów.

#include <string>
#include <algorithm>    // find

struct Uri
{
public:
std::wstring QueryString, Path, Protocol, Host, Port;

static Uri Parse(const std::wstring &uri)
{
    Uri result;

    typedef std::wstring::const_iterator iterator_t;

    if (uri.length() == 0)
        return result;

    iterator_t uriEnd = uri.end();

    // get query start
    iterator_t queryStart = std::find(uri.begin(), uriEnd, L'?');

    // protocol
    iterator_t protocolStart = uri.begin();
    iterator_t protocolEnd = std::find(protocolStart, uriEnd, L':');            //"://");

    if (protocolEnd != uriEnd)
    {
        std::wstring prot = &*(protocolEnd);
        if ((prot.length() > 3) && (prot.substr(0, 3) == L"://"))
        {
            result.Protocol = std::wstring(protocolStart, protocolEnd);
            protocolEnd += 3;   //      ://
        }
        else
            protocolEnd = uri.begin();  // no protocol
    }
    else
        protocolEnd = uri.begin();  // no protocol

    // host
    iterator_t hostStart = protocolEnd;
    iterator_t pathStart = std::find(hostStart, uriEnd, L'/');  // get pathStart

    iterator_t hostEnd = std::find(protocolEnd, 
        (pathStart != uriEnd) ? pathStart : queryStart,
        L':');  // check for port

    result.Host = std::wstring(hostStart, hostEnd);

    // port
    if ((hostEnd != uriEnd) && ((&*(hostEnd))[0] == L':'))  // we have a port
    {
        hostEnd++;
        iterator_t portEnd = (pathStart != uriEnd) ? pathStart : queryStart;
        result.Port = std::wstring(hostEnd, portEnd);
    }

    // path
    if (pathStart != uriEnd)
        result.Path = std::wstring(pathStart, queryStart);

    // query
    if (queryStart != uriEnd)
        result.QueryString = std::wstring(queryStart, uri.end());

    return result;

}   // Parse
};  // uri

Testy / Użycie

Uri u0 = Uri::Parse(L"http://localhost:80/foo.html?&q=1:2:3");
Uri u1 = Uri::Parse(L"https://localhost:80/foo.html?&q=1");
Uri u2 = Uri::Parse(L"localhost/foo");
Uri u3 = Uri::Parse(L"https://localhost/foo");
Uri u4 = Uri::Parse(L"localhost:8080");
Uri u5 = Uri::Parse(L"localhost?&foo=1");
Uri u6 = Uri::Parse(L"localhost?&foo=1:2:3");

u0.QueryString, u0.Path, u0.Protocol, u0.Host, u0.Port....
 17
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-15 04:00:36

Dla kompletności, jest jeden napisany w C, który można użyć (z odrobiną zawijania, bez wątpienia): http://uriparser.sourceforge.net/

[zgodny z RFC i obsługuje Unicode]


Oto bardzo prosty wrapper, którego używam do pobierania wyników analizy.

#include <string>
#include <uriparser/Uri.h>


namespace uriparser
{
    class Uri //: boost::noncopyable
    {
        public:
            Uri(std::string uri)
                : uri_(uri)
            {
                UriParserStateA state_;
                state_.uri = &uriParse_;
                isValid_   = uriParseUriA(&state_, uri_.c_str()) == URI_SUCCESS;
            }

            ~Uri() { uriFreeUriMembersA(&uriParse_); }

            bool isValid() const { return isValid_; }

            std::string scheme()   const { return fromRange(uriParse_.scheme); }
            std::string host()     const { return fromRange(uriParse_.hostText); }
            std::string port()     const { return fromRange(uriParse_.portText); }
            std::string path()     const { return fromList(uriParse_.pathHead, "/"); }
            std::string query()    const { return fromRange(uriParse_.query); }
            std::string fragment() const { return fromRange(uriParse_.fragment); }

        private:
            std::string uri_;
            UriUriA     uriParse_;
            bool        isValid_;

            std::string fromRange(const UriTextRangeA & rng) const
            {
                return std::string(rng.first, rng.afterLast);
            }

            std::string fromList(UriPathSegmentA * xs, const std::string & delim) const
            {
                UriPathSegmentStructA * head(xs);
                std::string accum;

                while (head)
                {
                    accum += delim + fromRange(head->text);
                    head = head->next;
                }

                return accum;
            }
    };
}
 11
Author: Elliot Cameron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-12 01:19:35

Klasa URI POCO może parsować adresy URL dla Ciebie. Poniższy przykład jest skróconą wersją tej W poco URI i slajdy UUID :

#include "Poco/URI.h"
#include <iostream>

int main(int argc, char** argv)
{
    Poco::URI uri1("http://www.appinf.com:88/sample?example-query#frag");

    std::string scheme(uri1.getScheme()); // "http"
    std::string auth(uri1.getAuthority()); // "www.appinf.com:88"
    std::string host(uri1.getHost()); // "www.appinf.com"
    unsigned short port = uri1.getPort(); // 88
    std::string path(uri1.getPath()); // "/sample"
    std::string query(uri1.getQuery()); // "example-query"
    std::string frag(uri1.getFragment()); // "frag"
    std::string pathEtc(uri1.getPathEtc()); // "/sample?example-query#frag"

    return 0;
}
 6
Author: Michael Mc Donnell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-16 20:09:14

Biblioteka Poco ma teraz klasę do rozcinania URI i podawania hosta, segmentów ścieżek i ciągów zapytań itp.

Http://www.appinf.com/docs/poco/Poco.URI.html

 5
Author: Tom Makin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-01 07:44:37

Facebook ' s Folly library może wykonać zadanie za ciebie łatwo. Po prostu użyj Uri klasy:

#include <folly/Uri.h>

int main() {
    folly::Uri folly("https://code.facebook.com/posts/177011135812493/");

    folly.scheme(); // https
    folly.host();   // code.facebook.com
    folly.path();   // posts/177011135812493/
}
 4
Author: Sun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-21 23:41:23
//sudo apt-get install libboost-all-dev; #install boost
//g++ urlregex.cpp -lboost_regex; #compile
#include <string>
#include <iostream>
#include <boost/regex.hpp>

using namespace std;

int main(int argc, char* argv[])
{
    string url="https://www.google.com:443/webhp?gws_rd=ssl#q=cpp";
    boost::regex ex("(http|https)://([^/ :]+):?([^/ ]*)(/?[^ #?]*)\\x3f?([^ #]*)#?([^ ]*)");
    boost::cmatch what;
    if(regex_match(url.c_str(), what, ex)) 
    {
        cout << "protocol: " << string(what[1].first, what[1].second) << endl;
        cout << "domain:   " << string(what[2].first, what[2].second) << endl;
        cout << "port:     " << string(what[3].first, what[3].second) << endl;
        cout << "path:     " << string(what[4].first, what[4].second) << endl;
        cout << "query:    " << string(what[5].first, what[5].second) << endl;
        cout << "fragment: " << string(what[6].first, what[6].second) << endl;
    }
    return 0;
}
 3
Author: velcrow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-07 23:56:06

Również interesujące może być http://code.google.com/p/uri-grammar / który podobnie jak Netlib Deana Michaela używa boost spirit do parsowania URI. Natknąłem się na prosty parser wyrażeń używając Boost::Spirit?

 2
Author: Ralf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:23

QT ma QUrl do tego. GNOME ma SoupURIw libsoup, które prawdopodobnie znajdziesz trochę bardziej lekkie.

 1
Author: Matthew Flaschen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-11 04:34:41

Jest nowo wydany Google-url lib:

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

Biblioteka zapewnia niskopoziomowe API do parsowania adresów url, a także abstrakcję wyższego poziomu o nazwie GURL. Oto przykład użycia tego:

#include <googleurl\src\gurl.h>

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

Mam dwie małe skargi na to: (1) chce domyślnie używać ICU do radzenia sobie z różnymi kodowaniami łańcuchów i (2) przyjmuje pewne założenia dotyczące logowania (ale myślę, że można je wyłączyć). Innymi słowy, biblioteka nie jest całkowicie samodzielny, ponieważ istnieje, ale myślę, że nadal jest to dobra podstawa do rozpoczęcia, zwłaszcza jeśli używasz już OIOM.

 1
Author: Mike Ellery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-23 17:18:09

Ta Biblioteka jest bardzo mała i lekka: https://github.com/corporateshark/LUrlParser

Jest to jednak tylko parsowanie, bez normalizacji/walidacji URL.

 1
Author: Sergey K.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-04 16:29:20

Możesz wypróbować bibliotekę open-source o nazwie C++ Rest SDK (stworzoną przez Microsoft, dystrybuowaną na licencji Apache 2.0). Może być zbudowany dla kilku platform, w tym Windows, Linux, OSX, iOS, Android). Istnieje klasa o nazwie web::uri, w której umieszczasz łańcuch znaków i możesz pobierać poszczególne komponenty URL. Oto przykład kodu (testowany na 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;

Wyjście będzie:

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

Istnieją również inne łatwe w użyciu metody, np. dostęp do poszczególnych pary atrybut / wartość z zapytania, podział ścieżki na komponenty, itd.

 1
Author: Vivit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-30 16:10:48

Jest jeszcze jedna biblioteka https://snapwebsites.org/project/libtld który obsługuje wszystkie możliwe domeny najwyższego poziomu i URI shema

 0
Author: Larytet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 10:21:41