从字符串中提取数据的优雅方法是什么?(可能使用boost库)?
Content-Type: text/plain
Content-Length: 15
Content-Date: 2/5/2013
Content-Request: Save
hello world
假设我有上面的字符串,想要提取所有字段,包括hello world文本。 有人能指出我正确的方向吗?
答案 0 :(得分:4)
尝试
<强> http://pocoproject.org/ 强>
附带HTTPServer和客户端实施
<强> http://cpp-netlib.github.com/ 强>
附带请求/响应处理
提升精神演示:http://liveworkspace.org/code/3K5TzT
你必须指定一个简单的语法(或复杂,如果你想'抓住'HTTP的所有细微之处)
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
typedef std::map<std::string, std::string> Headers;
typedef std::pair<std::string, std::string> Header;
struct Request { Headers headers; std::vector<char> content; };
BOOST_FUSION_ADAPT_STRUCT(Request, (Headers, headers)(std::vector<char>, content))
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
template <typename It, typename Skipper = qi::blank_type>
struct parser : qi::grammar<It, Request(), Skipper>
{
parser() : parser::base_type(start)
{
using namespace qi;
header = +~char_(":\n") > ": " > *(char_ - eol);
start = header % eol >> eol >> eol >> *char_;
}
private:
qi::rule<It, Header(), Skipper> header;
qi::rule<It, Request(), Skipper> start;
};
bool doParse(const std::string& input)
{
auto f(begin(input)), l(end(input));
parser<decltype(f), qi::blank_type> p;
Request data;
try
{
bool ok = qi::phrase_parse(f,l,p,qi::blank,data);
if (ok)
{
std::cout << "parse success\n";
std::cout << "data: " << karma::format_delimited(karma::auto_, ' ', data) << "\n";
}
else std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
return ok;
} catch(const qi::expectation_failure<decltype(f)>& e)
{
std::string frag(e.first, e.last);
std::cerr << e.what() << "'" << frag << "'\n";
}
return false;
}
int main()
{
const std::string input =
"Content-Type: text/plain\n"
"Content-Length: 15\n"
"Content-Date: 2/5/2013\n"
"Content-Request: Save\n"
"\n"
"hello world";
bool ok = doParse(input);
return ok? 0 : 255;
}
答案 1 :(得分:4)
答案 2 :(得分:2)
有几种解决方案。如果格式如此简单,您可以逐行读取文件。如果该行以键开头,您只需将其拆分即可获得该值。如果没有,则值为线本身。 STL非常容易且非常优雅。
如果语法更复杂,并且当您为标记添加了提升时,您可以考虑使用Boost Spirit来解析它并从中获取值。
答案 3 :(得分:2)
我认为最简单的解决方案是使用regular expressions。 C ++中有standard regexps 11 ,有些可以在boost中找到。
答案 4 :(得分:1)
您可以使用带有空格的string::find
来查找它们的位置,然后从该位置复制,直到找到'\n'
答案 5 :(得分:1)
如果您想编写代码来自行解析,请先查看HTTP spec。这将为您提供语法:
generic-message = start-line
*(message-header CRLF)
CRLF
[ message-body ]
start-line = Request-Line | Status-Line
所以我要做的第一件事是在CRLF上使用split()将其分解为复合线。然后,您可以遍历生成的向量。在你找到一个空白CRLF的元素之前,你正在解析一个标题,所以你拆分第一个':'来获得键和值。
点击空元素后,您正在解析响应正文。
警告:过去我自己做过这个,我可以告诉你并非所有网络服务器都对行结尾一致(你可能只找到一个CR或只有一个LF)而且并非所有浏览器/其他抽象层都是与他们传递给你的东西是一致的。因此,您可能会在您不期望的地方找到额外的CRLF,或者在您期望的地方找到CRLF。祝你好运。
答案 6 :(得分:0)
如果您准备手动展开循环,则可以使用std::istringstream
和提取运算符的正常重载(使用适当的操作符,例如get_time()
来处理日期)来提取数据。简单的方法。
另一种可能性是使用std::regex
来匹配所有模式,例如<string>:<string>
,并迭代所有匹配(egrep
语法似乎很有希望,如果你有几行要处理)。
或者,如果您想以困难的方式执行此操作,并且您的字符串具有特定语法,则可以使用Boost.Spirit轻松定义语法并生成解析器。
答案 7 :(得分:0)
如果您有权访问C + 11,则可以使用std :: regex(http://en.cppreference.com/w/cpp/regex)。
std::string input = "Content-Type: text/plain";
std::regex contentTypeRegex("Content-Type: (.+)");
std::smatch match;
if (std::regex_match(input, match, contentTypeRegex)) {
std::ssub_match contentTypeMatch = match[1];
std::string contentType = contentTypeMatch.str();
std::cout << contentType;
}
//else not found
在此处编译/运行版本:http://ideone.com/QTJrue
这个正则表达式是一个非常简化的情况,但它对于多个字段是相同的原则。