c++ - 如何解析后跟分号或换行符的条目(boost::spirit)?

标签 c++ boost-spirit boost-spirit-qi

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

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

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。但是,如果在此示例输入中 1.4 之后有空格,则会出错:

12 1.4
63 13.2

由于 no_skip,空间不匹配是有道理的,但我找不到解决方案。

最佳答案

这是我的看法。

  • 您可能想了解 qi::blank(除 qi::eol 外,它是 qi::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;
}

关于c++ - 如何解析后跟分号或换行符的条目(boost::spirit)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10669287/

相关文章:

c++ - 在 wndproc 中捕获 Ctrl+Alt 键

c++ - 将转义的换行符视为行继续

c++ - 使用 Spirit 将 std::vector<std::vector<double> 解析为结构体属性

c++ - Spirit X3 : attribute of alternative parser, 不是 `char` ,而是 `variant<char, char>`

c++ - 具有合成和继承属性的深度递归 qi 语法(解析器)

c++ - 数据结构 : Many (A) to many (B) relationship, 每个链接也有自己的数据 (C)

C++ 文字字符串和常量字符串引用参数

c++ - 当我使用 boost::bind 时,为什么 boost::spirit::qi 语义操作不能使用两个参数?

c++ - 如何将 Boost Spirit 解析的实体与其在输入流中的位置相关联?

c++ - 动态指针和对象