tag lib img c++ url uri

lib - ¿Manera fácil de analizar una url en plataforma cruzada de C++?



tag lib jstl (15)

Esta biblioteca es muy pequeña y liviana: https://github.com/corporateshark/LUrlParser

Sin embargo, solo está analizando, no hay normalización / validación de URL.

Necesito analizar una URL para obtener el protocolo, el host, la ruta y la consulta en una aplicación que estoy escribiendo en C ++. La aplicación está destinada a ser multiplataforma. Me sorprende que no pueda encontrar nada que haga esto en las bibliotecas de boost o POCO . ¿Es un lugar obvio que no estoy mirando? ¿Alguna sugerencia sobre librerías de código abierto apropiadas? ¿O es algo que tengo que hacer solo? No es muy complicado, pero parece una tarea tan común. Estoy sorprendido de que no haya una solución común.


Estaba buscando una biblioteca de URI independiente y sencilla para C ++ también. Al no poder encontrar uno, tomé la clase URI de Poco, recomendada en este tema, y ​​la hice independiente al hacer pocas modificaciones a los archivos fuente originales. Hecho de solo 2 archivos fuente y no requiere ninguna biblioteca externa, solo usa algunos encabezados de STL. He hecho algunas pruebas con compiladores GCC y MS y lo puse aquí en mi sitio web: http://ikk.byethost9.com/index.php?MainMenu=hef_uri_syntax Ha cambiado el nombre del espacio de nombres Poco -> hef y ha cambiado el nombre de URI de clase principal - > HfURISyntax . Se anima a cambiar el nombre de estos cuando se utiliza en sus propios proyectos. (Derechos de autor originales incluidos. Hay un documento de texto que contiene un resumen de las modificaciones).


Existe la nueva lib de google-url:

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

La biblioteca proporciona una API de análisis de URL de bajo nivel, así como una abstracción de nivel superior llamada GURL. Aquí hay un ejemplo que usa eso:

#include <googleurl/src/gurl.h> wchar_t url[] = L"http://www.facebook.com"; GURL parsedUrl (url); assert(parsedUrl.DomainIs("facebook.com"));

Dos pequeñas quejas que tengo con ella: (1) quiere usar ICU por defecto para tratar con diferentes codificaciones de cadenas y (2) hace algunas suposiciones sobre el registro (pero creo que se pueden deshabilitar). En otras palabras, la biblioteca no es completamente independiente ya que existe, pero creo que todavía es una buena base para comenzar, especialmente si ya está usando ICU.



Hay una biblioteca propuesta para la inclusión de Boost y le permite analizar fácilmente los URI HTTP. Utiliza Boost.Spirit y también se lanzó bajo la Licencia de software de Boost. La biblioteca es cpp-netlib para la que puede encontrar la documentación en http://cpp-netlib.github.com/ ; puede descargar la última versión de http://github.com/cpp-netlib/cpp-netlib/downloads .

El tipo relevante que querrá usar es boost::network::http::uri y está documentado here .



La biblioteca de Folly de Facebook puede hacer el trabajo por usted fácilmente. Simplemente usa la clase Uri :

#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/ }


La clase de URI de POCO puede analizar las URL por usted. El siguiente ejemplo es una versión abreviada de uno en las diapositivas POCO URI y 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; }


Para completar, hay uno escrito en C que puede usar (con un poco de envoltura, sin duda): http://uriparser.sourceforge.net/

[Compatible con RFC y admite Unicode]

Aquí hay un contenedor muy básico que he estado usando simplemente para obtener los resultados de un análisis sintáctico.

#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; } }; }


Puede probar la biblioteca de código abierto llamada C ++ REST SDK (creada por Microsoft, distribuida bajo Apache License 2.0). Se puede construir para varias plataformas, incluidas Windows, Linux, OSX, iOS, Android). Hay una clase llamada web::uri en la que ingresas una cadena y puedes recuperar componentes de URL individuales. Aquí hay un ejemplo de código (probado en 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;

El resultado será:

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

También hay otros métodos fáciles de usar, por ejemplo, para acceder a pares de atributos / valores individuales de la consulta, dividir la ruta en componentes, etc.


QT tiene QUrl para esto. GNOME tiene SoupURI en libsoup , que probablemente encuentres un poco más liviano.



Terriblemente lo siento, no pude evitarlo. : 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://.com/questions/2616011/parse-a.py?url=1"); cout << u.protocol() << ''/t'' << u.host() << ...


Versión de Wstring de arriba, agregué otros campos que necesitaba. Definitivamente podría ser refinado, pero lo suficientemente bueno para mis propósitos.

#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

Pruebas / Uso

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....


//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; }