2012-05-19 100 views
5

在Boost :: Spirit中,我该如何解析后跟分号或带有可选分号的换行符的条目?如何解析条目后跟分号或换行符(boost :: spirit)?

示例输入,其中每个条目是一个int和双:

12 1.4; 
63 13.2 
2423 56.4 ; 5 8.1 

下面是示例代码只是解析条目随后空白:

#include <iostream> 
#include <boost/foreach.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/support_istream_iterator.hpp> 
#include <boost/fusion/include/std_pair.hpp> 
namespace qi = boost::spirit::qi; 

typedef std::pair<int, double> Entry; 

template <typename Iterator, typename Skipper> 
struct MyGrammar : qi::grammar<Iterator, std::vector<Entry>(), Skipper> { 
    MyGrammar() : MyGrammar::base_type(entries) { 
    entry = qi::int_ >> qi::double_; 
    entries = +entry; 
    } 
    qi::rule<Iterator, Entry(), Skipper> entry; 
    qi::rule<Iterator, std::vector<Entry>(), Skipper> entries; 
}; 

int main() { 
    typedef boost::spirit::istream_iterator It; 
    std::cin.unsetf(std::ios::skipws); 
    It it(std::cin), end; 

    MyGrammar<It, qi::space_type> entry_grammar; 
    std::vector<Entry> entries; 
    if (qi::phrase_parse(it, end, entry_grammar, qi::space, entries) 
     && it == end) { 
    BOOST_FOREACH(Entry const& entry, entries) { 
     std::cout << entry.first << " and " << entry.second << std::endl; 
    } 
    } 
    else { 
    std::cerr << "FAIL" << std::endl; 
    exit(1); 
    } 
    return 0; 
} 

现在,来解析方式予想要(每个条目后面跟着分号或换行符,可选择分号),我将其替换为:

entries = +entry; 

通过这样的:

entries = +(entry >> (qi::no_skip[qi::eol] || ';')); 

其中boost::spirit操作者||指:(a后跟可选B)或b。

12 1.4 
63 13.2 

这是有道理的,因为no_skip的空间不匹配,但我没能找到一个解决办法:但是如果在这个例子中输入1.4后空间给出了一个错误。

+0

不是boost ::精神对于这么简单的任务来说有点矫枉过正? –

+0

我刚在这里做了一个小例子,我的真实语法比较复杂。 – Frank

回答

1

好吧,我发现这工作得很好:

entries = +(entry >> (qi::no_skip[*qi::lit(' ') >> qi::eol] || ';')); 

所以随之而来的问题就解决了。

但是,如果一个选项卡来ofter的1.4

12 1.4 
63 13.2 

这将是更好还是会失败,但它不会编译:

entries = +(entry >> (qi::no_skip[*qi::space >> qi::eol] || ';')); 

错误:

error: invalid static_cast from type ‘const std::pair<int, double\ 
>’ to type ‘int’ 
+1

我们再次见面。你可以通过使用'qi :: omit []'来解决这个问题,所以你不要将分隔符作为属性公开。但是,请参阅** [我的答案](http://stackoverflow.com/a/10670125/85371)**更典型的解决方案 – sehe

+0

谢谢,qi :: omit []非常有用。所以这一个很适合我:'条目= +(进入>>(齐:: no_skip [齐::省略[*补气::空白] >>齐:: EOL] || ';'));' – Frank

+0

但是,为什么我需要在'blank'上使用'omit []'而不是''eol'超出了我。人们会认为'eol'也会暴露,就像字符串'\ n'。 – Frank

6

这是我的要求。

  • 你可能想知道qi::blank(这是除了qi::eolqi::space)。这将消除对no_skip的需求。
  • 核心语法变为:

    entry = qi::int_ >> qi::double_; 
        entries = entry % +qi::char_("\n;") >> qi::omit[*qi::space]; 
    
  • 使用BOOST_SPIRIT_DEBUG来了解解析失败,为什么失败(如回溯)

输出:

12 and 1.4 
63 and 13.2 
2423 and 56.4 
5 and 8.1 

全码:

//#define BOOST_SPIRIT_DEBUG 
#include <iostream> 
#include <boost/foreach.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/support_istream_iterator.hpp> 
#include <boost/fusion/include/std_pair.hpp> 
namespace qi = boost::spirit::qi; 

typedef std::pair<int, double> Entry; 

template <typename Iterator, typename Skipper> 
struct MyGrammar : qi::grammar<Iterator, std::vector<Entry>(), Skipper> { 
    MyGrammar() : MyGrammar::base_type(entries) { 
     entry = qi::int_ >> qi::double_; 
     entries = 
      entry % +qi::char_("\n;")   // the data 
      >> qi::omit[*qi::space] > qi::eoi; // trailing whitespace 
     BOOST_SPIRIT_DEBUG_NODE(entry); 
     BOOST_SPIRIT_DEBUG_NODE(entries); 
    } 
    qi::rule<Iterator, Entry(), Skipper> entry; 
    qi::rule<Iterator, std::vector<Entry>(), Skipper> entries; 
}; 

int main() { 
    typedef boost::spirit::istream_iterator It; 
    std::cin.unsetf(std::ios::skipws); 
    It it(std::cin), end; 

    MyGrammar<It, qi::blank_type> entry_grammar; 
    std::vector<Entry> entries; 
    if (qi::phrase_parse(it, end, entry_grammar, qi::blank, entries) 
      && it == end) { 
     BOOST_FOREACH(Entry const& entry, entries) { 
      std::cout << entry.first << " and " << entry.second << std::endl; 
     } 
    } 
    else { 
     std::cerr << "FAIL" << std::endl; 
     exit(1); 
    } 
    return 0; 
} 
+0

感谢您的回答。问题是,我确实需要qi :: space作为整个队长。我的'entry'实际上比我的小例子更复杂,我需要跳过条目中的换行符,所以我不能使用qi :: blank作为整个队长。 – Frank

+0

我希望我的回答对您有所帮助,无论如何,概述:['该名单%parser'(http://www.boost.org/doc/libs/1_48_0/libs/spirit/doc/html/spirit/qi/reference/运算符/ list.html),'qi :: omit'以及'qi :: space'(它应该仍然被'qi :: skip(qi :: space)'[']'替代'qi :: no_skip [...]'因为它简化了你自己的表达式) – sehe

+0

+1 ty - 使用qi ::空间来代替qi :: blank是什么在杀死我...... – kfmfe04

相关问题