我正在尝试创建一个boost::spirit::qi
解析器,它将从编码的'中填充结构。串。字符串的内容是ascii十六进制数据,但我需要提取的字段不一定是字节对齐的。
我创建了一个简单的例子,我做了类似的事情,提取字符串并将字符串中的选择字符填充到结构中。最终版本需要更复杂的解码,但这证明了一般的想法。
我的解析器。我已经将十六进制字符串解析器绑定到构造结构的语义操作。
template <typename Iterator>
struct MyDataParser : qi::grammar<Iterator, MyData()>
{
static MyData ExtractMyData( const std::vector<char, std::allocator<char> >& val)
{
return MyData(val.at(0), val.at(3), val.at(6));
}
MyDataParser() : MyDataParser::base_type( decode_rule )
{
using namespace qi::labels;
auto data_string = qi::repeat(8)[qi::xdigit];
decode_rule %=
data_string[ boost::phoenix::bind(&ExtractMyData,_1) ]
;
}
qi::rule<Iterator, MyData()> decode_rule;
};
结构声明。需要两个构造函数来编译它。
struct MyData
{
char first_char;
char fourth_char;
char seventh_char;
MyData(char first = 0, char fourth = 0, char seventh = 0)
: first_char(first), fourth_char(fourth), seventh_char(seventh) {}
MyData( const std::vector<char, std::allocator<char> >& val)
: first_char(val.at(0)), fourth_char(val.at(3)), seventh_char(val.at(6)) {}
};
BOOST_FUSION_ADAPT_STRUCT(
MyData,
(char, first_char)
(char, fourth_char)
(char, seventh_char)
)
然而,这似乎有点像黑客。是否有内置机制来支持qi错误处理?理想情况下,将直接调用ctor而不是语义操作。
编辑 - 让我澄清一下我拍摄的内容
seh做了很好的回答我的问题,但我没有完全沟通。1)我想使用转换函数解码十六进制字符串。 2)使用未与结构耦合的解析器执行上述操作。
在一个完美的世界里,我会有一个看起来像这样的最终顶级规则:
auto rule %= char_
<< int_
<< hex_str_parser
<< repeat(8)[char_]
;
这将填充到类似于此定义的结构中:
struct MyData {
char my_char;
int my_int;
unsigned my_hex_value1; // extracted vai hex_str_parser
unsigned my_hex_value2; // extracted vai hex_str_parser
unsigned my_hex_value3; // extracted vai hex_str_parser
std::string my_string;
};
如何根据自定义规则定义从嵌入字符串中提取内容的规则,并无缝地融入另一个解析器?
答案 0 :(得分:1)
它并不像我在这里使用任何自动属性传播那样。因此,您可以不使用BOOST_FUSION_ADAPT_ *助手¹。
MyData
是一个聚合²所以如果你不想要它,你就不需要那个构造函数。 MyData{'a', '2', 'e'}
为aggregate initialization。
最后,我使用phoenix::function
使语义操作变得更漂亮:
<强> Live On Coliru 强>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
struct MyData { char first_char, fourth_char, seventh_char; };
template <typename Iterator>
struct MyDataParser : qi::grammar<Iterator, MyData()>
{
MyDataParser() : MyDataParser::base_type(start)
{
using namespace qi;
start = repeat(8)[xdigit] [_val = _decode(_1)];
}
private:
qi::rule<Iterator, MyData()> start;
struct DecodeF {
MyData operator()(const std::vector<char, std::allocator<char> >& val) const {
return { val.at(0), val.at(3), val.at(6) };
}
};
boost::phoenix::function<DecodeF> _decode;
};
int main() {
std::string const input = "12345678";
MyData data;
if (qi::parse(input.begin(), input.end(), MyDataParser<std::string::const_iterator>(), data))
std::cout << data.first_char << ":" << data.fourth_char << ":" << data.seventh_char << "\n";
}
打印
1:4:7
¹此外,他们是老式的。 C ++ 11允许BOOST_FUSION_ADAPT_STRUCT(MyData, first_char, fourth_char, seventh_char)
²事实上,在这种情况下它是POD