Boost Spirit X3如何条件化解析向量并处理可选后缀?
需求与正确实现
需求说明
要解析格式为(int ":" int )*的字符串,生成整数向量,规则如下:
- 配对的第二个值是奇数时,把第一个值加入结果向量
- 第二个值是偶数时,跳过该配对
: int部分可选,没写的话默认第二个值为1
你之前的错误尝试
尝试1:基础配对与向量生成(逻辑错误)
auto pair_ = x3::rule<class pair_, int>() = x3::int_ >> ":" >> x3::int_; auto vec = x3::rule<class vec, std::vector<int>>() = (*pair_[ ([](auto &c){ if(x3::_attr(c).second % 2) x3::_val(c).push_back(x3::_attr(c).first); }) ]);
问题:pair_规则的属性声明成了int,但实际是成对的整数,类型不匹配;同时语义动作的写法不符合X3规则,无法正确获取配对的两个值。
尝试2:处理可选后缀(类型不匹配)
auto pair_ = x3::rule<class pair_, int>() = x3::int_ >> ((":" >> x3::int_) | x3::attr(1));
问题:同样是属性类型错误,x3::int_ >> (xxx | attr(1))生成的是std::pair<int, int>类型的属性,但规则声明成了int,导致解析时属性绑定失败。
示例输入输出
输入:10 11:0 12:3
预期输出:[10, 12]
正确代码实现
#include <boost/spirit/home/x3.hpp> #include <vector> #include <utility> #include <iostream> namespace x3 = boost::spirit::x3; int main() { // 定义配对规则,属性为成对整数,处理可选的": int"(默认值1) auto pair_rule = x3::rule<class pair_tag, std::pair<int, int>>{} = x3::int_ >> ((":" >> x3::int_) | x3::attr(1)); // 定义向量生成规则:遍历所有配对,筛选符合条件的加入结果 auto vec_rule = x3::rule<class vec_tag, std::vector<int>>{} = *x3::omit[ pair_rule([](auto& ctx) { const auto& pair = x3::_attr(ctx); // 第二个值为奇数时,将第一个值加入结果 if (pair.second % 2 != 0) { x3::_val(ctx).push_back(pair.first); } }) ]; // 测试输入解析 std::string input = "10 11:0 12:3"; std::vector<int> result; auto iter = input.begin(); const auto end = input.end(); // 使用phrase_parse处理输入中的空白符 bool parse_success = x3::phrase_parse(iter, end, vec_rule, x3::space, result); // 输出结果 if (parse_success && iter == end) { std::cout << "["; for (size_t i = 0; i < result.size(); ++i) { if (i != 0) std::cout << ", "; std::cout << result[i]; } std::cout << "]\n"; } else { std::cout << "解析失败,剩余未解析内容:" << std::string(iter, end) << "\n"; } return 0; }
核心修正点
- 属性类型匹配:把
pair_rule的属性明确声明为std::pair<int, int>,和规则生成的属性类型一致,避免绑定错误。 - 语义动作逻辑:在遍历每个配对时,直接获取配对的两个值,判断第二个值是否为奇数,符合条件就将第一个值加入结果向量。
- 空白处理:用
phrase_parse配合x3::space,自动跳过输入中的空格分隔符,符合示例的输入格式。
内容的提问来源于stack exchange,提问作者Bubaya
相关产品推荐
相关产品推荐

