【发布时间】:2014-12-29 18:07:19
【问题描述】:
我通常熟悉使用 qi::attr 为解析输入中的缺失条目实现“默认值”。但是当需要从早期的解析中提取默认值时,我还没有看到如何执行此操作。
我正在尝试解析为以下结构:
struct record_struct {
std::string Name;
uint8_t Distance;
uint8_t TravelDistance;
std::string Comment;
};
从一个相对简单的“(text)(number)[(number)][//comment]”格式开始,其中第二个数字和注释都是可选的。如果第二个数字不存在,则其值应设置为与第一个数字相同。
下面是一个简化的工作代码示例,它不能完全按照我的意愿行事。这个版本只是默认为0 而不是正确的值。如果可能的话,我想将两个整数的解析隔离到一个单独的解析器规则中,而不放弃使用 fusion 结构。
我尝试过但没有编译的东西:
- 将
qi::attr(0)替换为qi::attr(qi::_2) - 尝试使用语义操作 `qi::attr(0)[qi::_3 = qi::_2] 对 attr 匹配进行事后修改
完整的测试代码:
#include <string>
#include <cstdint>
#include <boost/spirit/include/qi.hpp>
struct record_struct {
std::string Name;
uint8_t Distance;
uint8_t TravelDistance;
std::string Comment;
};
BOOST_FUSION_ADAPT_STRUCT(
record_struct,
(std::string, Name)
(uint8_t, Distance)
(uint8_t, TravelDistance)
(std::string, Comment)
)
std::ostream &operator<<(std::ostream &o, const record_struct &s) {
o << s.Name << " (" << +s.Distance << ":" << +s.TravelDistance << ") " << s.Comment;
return o;
}
bool test(std::string s) {
std::string::const_iterator iter = s.begin();
std::string::const_iterator end = s.end();
record_struct result;
namespace qi = boost::spirit::qi;
bool parsed = boost::spirit::qi::parse(iter, end, (
+(qi::alnum | '_') >> qi::omit[+qi::space]
>> qi::uint_ >> ((qi::omit[+qi::space] >> qi::uint_) | qi::attr(0))
>> ((qi::omit[+qi::space] >> "//" >> +qi::char_) | qi::attr(""))
), result);
if (parsed) std::cout << "Parsed: " << result << "\n";
else std::cout << "Failed: " << std::string(iter, end) << "\n";
return parsed;
}
int main(int argc, char **argv) {
if (!test("Milan 20 22")) return 1;
if (!test("Paris 8 9 // comment")) return 1;
if (!test("London 5")) return 1;
if (!test("Rome 1 //not a real comment")) return 1;
return 0;
}
输出:
Parsed: Milan (20:22)
Parsed: Paris (8:9) comment
Parsed: London (5:0)
Parsed: Rome (1:0) not a real comment
我想看的输出:
Parsed: Milan (20:22)
Parsed: Paris (8:9) comment
Parsed: London (5:5)
Parsed: Rome (1:1) not a real comment
【问题讨论】:
标签: c++ boost-spirit boost-spirit-qi