【问题标题】:Boost.Spirit.x3 avoid collapsing two consecutive attributes of the same type into a vectorBoost.Spirit.x3 避免将相同类型的两个连续属性折叠成一个向量
【发布时间】:2016-09-04 20:21:58
【问题描述】:

我正在尝试学习 Boost.Spirit,但我发现了一个困难。

我正在尝试将字符串解析为以下结构:

struct employee {
    std::string name;
    std::string location;
};

似乎当两个具有相同类型的属性背靠背时,它们(逻辑上)折叠成该类型的std::vector。由于该规则,以下解析器

+x3::ascii::alnum >>
    +x3::space >>
    +x3::ascii::alnum

将具有std::vector<std::string> 的属性。

但我试图将其解析为struct,这意味着对我来说理想的属性是boost::fusion::tuple<std::string, std::string>,所以我可以调整我的结构来适应它。

不工作代码的完整版本(参考上面):

// Example program
#include <iostream>
#include <string>

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>


struct employee {
    std::string name;
    std::string location;
};

BOOST_FUSION_ADAPT_STRUCT(employee, 
    (std::string, name),
    (std::string, location)
)

namespace x3 = boost::spirit::x3;

x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def = 
    +x3::ascii::alnum >>
    +x3::space >>
    +x3::ascii::alnum
    ;
BOOST_SPIRIT_DEFINE(parse_emp);

int main()
{
    std::string input = "Joe Fairbanks";
    
    employee ret;
    
    x3::parse(input.begin(), input.end(), parse_emp, ret);
    
    std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << std::endl;
}

See it live

此代码触发static_assert,告诉我我的属性不正确:

error: static_assert failed "Attribute does not have the expected size."

用命令

clang++ -std=c++14 test.cpp

(在 GCC 下它也会失败)。

我尝试过的

我找到了解决这个问题的方法,但它很乱,我不敢相信这是最干净的方法:

// Example program
#include <iostream>
#include <string>

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>


struct employee {
    std::string name;
    std::string location;
};

namespace x3 = boost::spirit::x3;

x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def = 
    x3::eps [
    ([](auto& ctx) {
        x3::_val(ctx) = employee{};
    })
    ]>>
    (+x3::ascii::alnum)[
    ([](auto& ctx) {
        x3::_val(ctx).name = x3::_attr(ctx);
    })
    ]>>
    +x3::space >>
    (+x3::ascii::alnum)[
    ([](auto& ctx) {
        x3::_val(ctx).location = x3::_attr(ctx);
    })
    ]
    ;
BOOST_SPIRIT_DEFINE(parse_emp);

int main()
{
    std::string input = "Joe Fairbanks";
    
    employee ret;
    
    x3::parse(input.begin(), input.end(), parse_emp, ret);
    
    std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << std::endl;
}

See it live

我真的不喜欢那个解决方案:它有点破坏了精神的惊人表现力,让它变得超级丑陋,如果我想在 employee 结构中添加新字段,那么我必须添加一个额外的 lambda,而不是仅仅更新我的BOOST_FUSION_ADAPT_STRUCT,这要容易得多。

所以问题是:有没有办法(希望)干净地将两个相同类型的连续属性从std::vector 拆分为boost::fusion::vector

在此先感谢您 ;)。

【问题讨论】:

    标签: c++ boost c++14 boost-spirit boost-spirit-x3


    【解决方案1】:

    问题在于,与字符文字不同,x3::space 有一个属性。因此,您没有两个由空格分隔的单独字符序列的属性,而是一个包含空格的大字符序列的属性。

    The omit directive 是您所追求的,只需添加一次,您的“无效代码”就可以工作。 :-]

    // Example program
    #include <string>
    #include <iostream>
    
    #include <boost/fusion/include/adapt_struct.hpp>
    #include <boost/spirit/home/x3.hpp>
    
    namespace x3 = boost::spirit::x3;
    
    struct employee {
        std::string name;
        std::string location;
    };
    BOOST_FUSION_ADAPT_STRUCT(employee, name, location)
    
    x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
    auto parse_emp_def
        =      +x3::ascii::alnum
            >>  x3::omit[+x3::space]
            >> +x3::ascii::alnum
        ;
    BOOST_SPIRIT_DEFINE(parse_emp)
    
    int main()
    {
        std::string const input = "Joe Fairbanks";
    
        employee ret;
        x3::parse(input.begin(), input.end(), parse_emp, ret);
    
        std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << '\n';
    }
    

    Online Demo

    【讨论】:

    • 这是一个美好的一天,在我找到问题之前,精神问题的答案就已经存在了 :) +1
    • @sehe:哈!这肯定是我第一次在 X3 问题上击败你,但是,这是一个非常简单的问题。 ;-]
    • @Russel 我建议使用船长而不是显式空格(请参阅stackoverflow.com/questions/17072987/…)。 Live on Coliru.
    • 我希望 omit 指令只是从字符序列中删除空格,而不是将其分成两个。为什么会这样?
    • @RussellGreene : omit 特别是 没有 属性,这是关键。 +x3::ascii::alnum &gt;&gt; +' ' &gt;&gt; +x3::ascii::alnum 不需要omit 也可以正常工作,因为字符文字也没有属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-28
    • 2012-01-06
    • 1970-01-01
    • 2016-10-19
    • 1970-01-01
    相关资源
    最近更新 更多