使用boost:qi解析两个字符串向量

时间:2017-04-11 04:21:12

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

我是使用qi的新手,遇到了困难。我希望解析一个输入,如:

X + Y + Z,A + B

分为两个字符串向量。

我有代码执行此操作,但仅当语法解析单个字符时。理想情况下,以下行应该是可读的:

<+> Xi + Ye + Zou,Ao + Bi

使用elem = +(char_ - '+') % '+'之类的简单替换无法解析,因为它会消耗第一个元素上的','但我还没有发现一个简单的方法。

这是我的单字符代码,供参考:

#include <bits/stdc++.h>

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

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

typedef std::vector<std::string> element_array;

struct reaction_t
{
  element_array reactants;
  element_array products;
};

BOOST_FUSION_ADAPT_STRUCT(reaction_t, (element_array, reactants)(element_array, products))

template<typename Iterator>
struct reaction_parser : qi::grammar<Iterator,reaction_t(),qi::blank_type>
 {
    reaction_parser() : reaction_parser::base_type(reaction)
    {
        using namespace qi;

    elem = char_ % '+';
    reaction = elem >> ',' >> elem;

    BOOST_SPIRIT_DEBUG_NODES((reaction)(elem));
    }
    qi::rule<Iterator, reaction_t(), qi::blank_type> reaction;
    qi::rule<Iterator, element_array(), qi::blank_type> elem;
};
int main()
{

    const std::string input = "X + Y + Z, A + B";
    auto f = begin(input), l = end(input);

    reaction_parser<std::string::const_iterator> p;
    reaction_t data;

    bool ok = qi::phrase_parse(f, l, p, qi::blank, data);

    if (ok) std::cout << "success\n";
    else    std::cout << "failed\n";

    if (f!=l)
        std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

1 个答案:

答案 0 :(得分:3)

  

使用简单的替代品,例如elem = +(char_ - &#39; +&#39;)%&#39; +&#39;无法解析,因为它会消耗&#39;,&#39;在第一个元素,但我没有发现一个简单的方法。

嗯,完整的(脑死亡)简单解决方案是使用+(char_ - '+' - ',')+~char_("+,")

但是,我确实element的规则更具体,例如:

    elem     = qi::lexeme [ +alpha ] % '+';
  

关于词汇和船长,请参阅Boost spirit skipper issues

<强> Live On Coliru

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

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

typedef std::vector<std::string> element_array;

struct reaction_t
{
    element_array reactants;
    element_array products;
};

BOOST_FUSION_ADAPT_STRUCT(reaction_t, (element_array, reactants)(element_array, products))

template<typename Iterator>
struct reaction_parser : qi::grammar<Iterator,reaction_t(),qi::blank_type>
{
    reaction_parser() : reaction_parser::base_type(reaction) {
        using namespace qi;

        elem     = qi::lexeme [ +alpha ] % '+';
        reaction = elem >> ',' >> elem;

        BOOST_SPIRIT_DEBUG_NODES((reaction)(elem));
    }
    qi::rule<Iterator, reaction_t(), qi::blank_type> reaction;
    qi::rule<Iterator, element_array(), qi::blank_type> elem;
};

int main()
{
    reaction_parser<std::string::const_iterator> p;

    for (std::string const input : {
            "X + Y + Z, A + B",
            "Xi + Ye + Zou , Ao + Bi",
            })
    {
        std::cout << "----- " << input << "\n";
        auto f = begin(input), l = end(input);

        reaction_t data;

        bool ok = qi::phrase_parse(f, l, p, qi::blank, data);

        if (ok) {
            std::cout << "success\n";
            for (auto r : data.reactants) { std::cout << "reactant: " << r << "\n"; }
            for (auto p : data.products)  { std::cout << "product:  " << p << "\n"; }
        }
        else
            std::cout << "failed\n";

        if (f != l)
            std::cout << "Remaining unparsed: '" << std::string(f, l) << "'\n";
    }
}

印刷:

----- X + Y + Z, A + B
success
reactant: X
reactant: Y
reactant: Z
product:  A
product:  B
----- Xi + Ye + Zou , Ao + Bi
success
reactant: Xi
reactant: Ye
reactant: Zou
product:  Ao
product:  Bi