C ++从字符串中提取数据

时间:2013-02-05 19:40:34

标签: c++ boost

从字符串中提取数据的优雅方法是什么?(可能使用boost库)?

Content-Type: text/plain
Content-Length: 15
Content-Date: 2/5/2013
Content-Request: Save

hello world

假设我有上面的字符串,想要提取所有字段,包括hello world文本。 有人能指出我正确的方向吗?

8 个答案:

答案 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

这个正则表达式是一个非常简化的情况,但它对于多个字段是相同的原则。