boost :: spirit。解析(名称)(说明)文本到地图

问题描述:

我目前的工作在未来的格式解析数据库架构中的文本文件:boost :: spirit。解析(名称)(说明)文本到地图

(table_name) (table_description) 

元素之间的分隔符是双倍返还(\n\n) 我需要解析这到地图上,使用boost::spirit进行解析。

问题是table_description也可以包含双重返回(\n\n)。

table_name有严格的格式,这是*qi::char_("a-z0-9_")table_description可以包含任何字符,但以后总是从大写开始。

任何想法如何为此解析器创建语法?

+1

“*元素之间的分隔符是双倍返还*” ...... “*的'table_description'也含有双重回报*”你的格式基本上被打破了。 – ildjarn

这与Spirit文档中的文章非常相似:Parsing a List of Key-Value Pairs Using Spirit.Qi(2009年11月15日)。

最简单的语法,我能为这个想的,依赖于括号:

start   = pair % "\n\n"; 
    parenthesized = '(' > *(char_ - ')') > ')'; 
    pair   = parenthesized >> "\n\n" >> parenthesized; 

你当然可以提高它要求对表的名称和说明确切的语法(从资金,如)你需要,但以上是为了说明。

唯一/漂亮/位:

  • 使用char_ - ')'到_greedily匹配括号内的任何(注意,这还不支持嵌套集合括号)
  • 对于使用融合适配器的std ::对解析成标准::对直接
  • 使用qi::blank(未qi::space)船长的,以避免忽视换行符

这是一个完整的示例:

//#define BOOST_SPIRIT_DEBUG 
#include <boost/fusion/adapted/std_pair.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/karma.hpp> 

namespace qi = boost::spirit::qi; 
namespace karma = boost::spirit::karma; 

typedef std::map<std::string, std::string> map_t; 

template <typename It, typename Skipper = qi::space_type> 
    struct parser : qi::grammar<It, map_t(), Skipper> 
{ 
    parser() : parser::base_type(start) 
    { 
     using namespace qi; 
     // using phx::bind; using phx::ref; using phx::val; 

     start   = pair % "\n\n"; 
     pair   = parenthesized >> "\n\n" >> parenthesized; 
     parenthesized = '(' > *(char_ - ')') > ')'; 

     BOOST_SPIRIT_DEBUG_NODE(parenthesized); 
     BOOST_SPIRIT_DEBUG_NODE(pair); 
     BOOST_SPIRIT_DEBUG_NODE(start); 
    } 

    private: 
    qi::rule<It, std::string(), Skipper > parenthesized; 
    qi::rule<It, std::pair<std::string, std::string>(), Skipper> pair; 
    qi::rule<It, std::map <std::string, std::string>(), Skipper> start; 
}; 

template <typename C, typename Skipper> 
    bool doParse(const C& input, const Skipper& skipper) 
{ 
    auto f(std::begin(input)), l(std::end(input)); 

    parser<decltype(f), Skipper> p; 
    map_t data; 

    try 
    { 
     bool ok = qi::phrase_parse(f,l,p,skipper,data); 
     if (ok) 
     { 
      std::cout << "parse success\n"; 
      std::cout << "data: " << karma::format(
       (karma::auto_ << ": \"" << karma::auto_ << "\"") % karma::eol, 
       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; 
} 

template <typename C> 
    bool doParse(const C& input) 
{ 
    return doParse(input, qi::blank); 
} 

int main() 
{ 
    const std::string input = "(table_name)\n\n(table_description)\n\n(other_table)\n\n(other\n\ndescription)"; 
    bool ok = doParse(input); 

    return ok? 0 : 255; 
} 

测试输出:

parse success 
data: other_table: "other 

description" 
table_name: "table_description" 
+0

非常好!谢谢! – Vitaliy