提升精神气:在Kleene Star解析器中省略元素

时间:2013-11-18 00:42:55

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

我想解析特殊构造并将其余部分抛弃。但我不想使用船长。

我想得到这些结构的向量,所以我使用Kleene Star解析器作为主要规则。但是,每次丢弃某些东西时,都会在向量中插入一个默认的构造元素。

这是一个组成的例子。它只是寻找字符串Test并抛弃其余部分,至少这是计划。但每次规则garbage成功时,它会将一个默认构造项添加到规则all中的向量中,输出为7的输出为1.如何将Spirit添加到向量中规则item成功了吗?

#define BOOST_SPIRIT_USE_PHOENIX_V3

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/phoenix.hpp>

#include <iostream>
#include <string>
#include <vector>

namespace qi = boost::spirit::qi;

struct container {
  std::string name;
  bool        dummy;
};
BOOST_FUSION_ADAPT_STRUCT(::container,
                          (std::string, name)
                          (bool, dummy))

int main() {
  typedef std::string::const_iterator iterator;

  qi::rule<iterator, std::vector<container>()> all;
  qi::rule<iterator, container()> item;
  qi::rule<iterator, std::string()> string_rule;
  qi::rule<iterator> garbage;

  all = *(garbage | item);
  garbage = qi::char_ - qi::lit("Test");
  string_rule = qi::string("Test");
  item = string_rule >> qi::attr(true);

  std::vector<container> ast;

  std::string input = "blaTestbla";

  iterator first = input.begin();
  iterator last = input.end();

  bool result = qi::parse(first, last, all, ast);
  if (result) {
    result = first == last;
  }

  if (result) {
    std::cout << "Parsed " << ast.size() << " element(s)" << std::endl;
  } else {
    std::cout << "failure" << std::endl;
  }

}

2 个答案:

答案 0 :(得分:3)

由于sehe的答案或多或少用于教育目的,我们现在有几个解决方案:

*garbage >> -(item % *garbage) >> *garbage

*garbage >> *(item >> *garbage)

all = *(garbage | item[phx::push_back(qi::_val,qi::_1)]);

来自cv_and_he的解决方案:

#define BOOST_SPIRIT_USE_PHOENIX_V3

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/phoenix.hpp>

#include <iostream>
#include <string>
#include <vector>

namespace qi = boost::spirit::qi;

struct container {
  std::string name;
  bool        dummy;
};
BOOST_FUSION_ADAPT_STRUCT(::container,
                          (std::string, name)
                          (bool, dummy))

struct container_vector {   //ADDED
    std::vector<container> data;
};

namespace boost{ namespace spirit{ namespace traits //ADDED
{
    template <>
    struct is_container<container_vector> : boost::mpl::true_ {};

    template <>
    struct container_value<container_vector> {
        typedef optional<container> type;
    };

    template <>
    struct push_back_container<container_vector,optional<container> > {
        static bool call(container_vector& cont, const optional<container>& val) {
            if(val)
                cont.data.push_back(*val);
            return true;
        }
    };
}}}

int main() {
  typedef std::string::const_iterator iterator;

  qi::rule<iterator, container_vector()> all; //CHANGED
  qi::rule<iterator, container()> item;
  qi::rule<iterator, std::string()> string_rule;
  qi::rule<iterator> garbage;

  all = *(garbage | item);
  garbage = qi::char_ - qi::lit("Test");
  string_rule = qi::string("Test");
  item = string_rule >> qi::attr(true);

  container_vector ast;     //CHANGED

  std::string input = "blaTestbla";

  iterator first = input.begin();
  iterator last = input.end();

  bool result = qi::parse(first, last, all, ast);
  if (result) {
    result = first == last;
  }

  if (result) {
    std::cout << "Parsed " << ast.data.size() << " element(s)" << std::endl;   //CHANGED 
  } else {
    std::cout << "failure" << std::endl;
  }

}

虽然我不想使用船长,但我最终得到了:

start = qi::skip(garbage.alias())[*item];

在我的不科学测试中,使用我的生产规则使用Linux内核的c文件,最后一个解决方案是最快的(1-2%)。

答案 1 :(得分:2)

快速解决方案(不一定是最有效的)将是

all         = -(item - garbage) % +garbage;

打印:

Parsed 3 element(s)

查看 Live on Coliru