提升灵气:省略克莱恩星辰解析器中的元素

Boost Spirit Qi: Omit element in Kleene Star parser

本文关键字:元素 克莱恩      更新时间:2023-10-16

我想解析特殊的结构并扔掉其余的。但我不想使用船长。

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

这是一个虚构的例子。它只是寻找字符串Test并扔掉其余的,至少这是计划。但是每次规则garbage成功时,它都会在规则all向量中添加一个默认构造项,给出 7 的输出 1。如果规则item成功,我怎么能告诉 Spirit 只是添加到向量中?

#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;
  }
}

由于 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%)。

快速修复(不一定是性能最高的)是

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

它打印:

Parsed 3 element(s)

在科里鲁现场观看