简单的方法来parsingC ++跨平台的url?
我需要parsing一个URL来获取我用C ++编写的应用程序中的协议,主机,path和查询。 该应用程序旨在跨平台。 我很惊讶我无法find任何这样做在推动或POCO图书馆。 是不是很明显,我不看? 任何build议在适当的开放源代码库? 或者这是我只需要做我自己的东西? 这不是非常复杂,但似乎是这样一个共同的任务,我很惊讶,没有一个共同的解决scheme。
有一个图书馆提出了Boost包含,并允许您轻松地parsingHTTP URI。 它使用Boost.Spirit并且在Boost软件许可下发布。 该库是cpp-netlib,您可以在http://cpp-netlib.github.com/find相关文档; – 您可以从http://github.com/cpp-netlib/cpp-netlib下载最新版本/下载; 。
您将要使用的相关types是boost::network::http::uri
并在此处进行了说明 。
非常抱歉,忍不住。 :■
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() << ...
上面的Wstring版本,增加了我需要的其他字段。 可以绝对精致,但足够我的目的。
#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
testing/用法
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....
为了完整性,有一个用C语言写的,你可以使用(毫无疑问): http : //uriparser.sourceforge.net/
[RFC兼容并支持Unicode]
这是我用来简单地获取parsing结果的一个非常基本的包装器。
#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; } }; }
Poco库现在有一个parsingURI并反馈主机,path段和查询string的类。
POCO的URI类可以为你parsingURL。 以下示例是POCO URI和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; }
Facebook的Folly图书馆可以为您轻松完成工作。 只需使用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/ }
//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; }
QT有这个QUrl 。 GNOME在libsoup中有SoupURI ,你可能会发现它更轻一点 。
有新发布的谷歌url库:
http://code.google.com/p/google-url/
该库提供了一个低级别的URLparsingAPI以及一个名为GURL的更高级别的抽象。 这里有一个例子:
#include <googleurl\src\gurl.h> wchar_t url[] = L"http://www.facebook.com"; GURL parsedUrl (url); assert(parsedUrl.DomainIs("facebook.com"));
我有两个小的抱怨:(1)默认情况下要使用ICU来处理不同的string编码;(2)对日志logging做一些假设(但我认为它们可以被禁用)。 换句话说,图书馆并不是完全独立的,但是我认为这是一个很好的基础,尤其是如果你已经在使用ICU的话。
这个库非常小巧轻便: https : //github.com/corporateshark/LUrlParser
但是,它只是parsing,没有URL标准化/validation。
也有兴趣的可以是http://code.google.com/p/uri-grammar/ ,喜欢Dean Michael的netlib使用boost精神来parsing一个URI。 使用Boost :: Spirit在Simple expression parser例子中find它?
我也在为C ++寻找简单的独立URI库。 无法find一个我从POCO的URI类,build议在这个主题,并通过对原始源文件进行less量修改使其独立。 只有2个源文件,并不需要任何exgernal库,只使用STLless数头。 我已经使用GCC和MS编译器进行了一些testing,并将其放在我的网站上: http : //ikk.byethost9.com/index.php?MainMenu=hef_uri_syntax它已经重命名命名空间Poco – > hef并将其重命名为主类URI – > HfURISyntax 。 它鼓励在您自己的项目中使用时重命名这些。 (包含原始版权,包含修改摘要的文本文档。)
您可以尝试使用名为C ++ REST SDK的开源库(由Microsoft创build,在Apache License 2.0下发行)。 它可以为几个平台,包括Windows,Linux,OSX,iOS,Android)构build。 有一个名为web::uri
的类,你可以放入一个string,并可以检索单独的URL组件。 这是一个代码示例(在Windows上testing):
#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
还有其他易于使用的方法,例如,从查询中访问各个属性/值对,将path拆分为组件等。