提神气:用元组向量绑定到struct 《升腾精神》的解析当然是C++的一个独特应用,一个具有陡峭学习曲线的应用。在这种情况下,我试图解析一个包含语法正确的C++列表初始化的字符串,该代码包含 >代码> STD::tuple < /代码>。下面是结构的声明: typedef std::vector<std::tuple<std::string, int>> label_t; struct BulkDataParmas { std::string strUUID; short subcam; long long pts_beg; long long pts_len; long long pts_gap; label_t labels; };
下面是要分析的示例字符串:提神气:用元组向量绑定到struct 《升腾精神》的解析当然是C++的一个独特应用,一个具有陡峭学习曲线的应用。在这种情况下,我试图解析一个包含语法正确的C++列表初始化的字符串,该代码包含 >代码> STD::tuple < /代码>。下面是结构的声明: typedef std::vector<std::tuple<std::string, int>> label_t; struct BulkDataParmas { std::string strUUID; short subcam; long long pts_beg; long long pts_len; long long pts_gap; label_t labels; };,c++,parsing,boost,boost-spirit,boost-spirit-qi,C++,Parsing,Boost,Boost Spirit,Boost Spirit Qi,下面是要分析的示例字符串: "{ \"68965363-2d87-46d4-b05d-f293f2c8403b\", 0, 1583798400000000, 86400000000, 600000000, { { \"motorbike\", 5 }, { \"aeroplane\", 6 } } };" 我在回答我自己的问题。我犯了两个错误。首先,规则label的属性类型错误,std::string()而不是std::tuple() 第二个错误是我需要#包括。我发现这只是偶然的,因为这不在
"{ \"68965363-2d87-46d4-b05d-f293f2c8403b\", 0, 1583798400000000, 86400000000, 600000000, { { \"motorbike\", 5 }, { \"aeroplane\", 6 } } };"
我在回答我自己的问题。我犯了两个错误。首先,规则
label
的属性类型错误,std::string()
而不是std::tuple()
第二个错误是我需要#包括。我发现这只是偶然的,因为这不在Spirit 2.5文档中
template <typename Iterator>
struct load_parser : boost::spirit::qi::grammar<Iterator, BulkDataParmas(), boost::spirit::ascii::space_type>
{
load_parser() : load_parser::base_type(start)
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
using qi::attr;
using qi::short_;
using qi::int_;
using qi::long_long;
using qi::lit;
using qi::xdigit;
using qi::lexeme;
using ascii::char_;
using boost::proto::deep_copy;
auto hex2_ = deep_copy(xdigit >> xdigit >> xdigit >> xdigit);
auto hex4_ = deep_copy(hex2_ >> hex2_);
auto hex6_ = deep_copy(hex4_ >> hex2_);
auto fmt_ = deep_copy('"' >> hex4_ >> char_('-') >> hex2_ >> char_('-') >> hex2_ >> char_('-') >> hex2_ >> char_('-') >> hex6_ >> '"');
uuid = qi::as_string[fmt_];
quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];
label = '{' >> quoted_string >> ',' >> int_ >> '}';
start = '{' >> uuid >> ',' >> short_ >> ',' >> long_long >> ',' >> long_long >> ',' >> long_long >> ',' >> '{' >> -(label >> *(',' >> label)) >>'}' >> '}';
// start = '{' >> uuid >> ',' >> short_ >> ',' >> long_long >> ',' >> long_long >> ',' >> long_long >> '}';
}
private:
boost::spirit::qi::rule<Iterator, std::string()> uuid;
boost::spirit::qi::rule<Iterator, std::string()> quoted_string;
boost::spirit::qi::rule<Iterator, std::tuple<std::string, int>(), boost::spirit::ascii::space_type> label;
boost::spirit::qi::rule<Iterator, BulkDataParmas(), boost::spirit::ascii::space_type> start;
};
模板
结构加载语法分析器:boost::spirit::qi::grammar
{
load_parser():load_parser::base_type(开始)
{
名称空间qi=boost::spirit::qi;
名称空间ascii=boost::spirit::ascii;
使用qi::attr;
使用qi::short_u2;;
使用qi::int_;
使用气::龙龙;
使用qi::lit;
使用qi::xdigit;
使用气:词素;
使用ascii::char;
使用boost::proto::deep_copy;
自动hex2=深度复制(xdigit>>xdigit>>xdigit>>xdigit);
自动hex4=深度复制(hex2\u>>hex2\uU);
自动hex6=深度复制(hex4->hex2);
自动fmt=深拷贝('''>>hex4'>>char'-'>>hex2'>>char'-'>>hex2'>>char'-'>>hex2'>>char'-'>>hex2'>>char'-'>>hex6');
uuid=qi::as_字符串[fmt_];
quoted_string%=词素[''''>>+(字符'''')>'''];
label='{'>>引用的字符串>>','>>int'>>'}';
开始=“{'>>uuid>>”、“>>short'>>”、“>>long'>>”、“>>long'>>”、“>>long'>>”、“>>”{'>>-(标签>>*(',“>>标签))>>”}>>”;
//开始=“{'>>uuid>>”、“>>短”、“>>长”、“>>长”、“>>长”、“>>长”>>”;
}
私人:
boost::spirit::qi::rule uuid;
boost::spirit::qi::规则引用\u字符串;
boost::spirit::qi::规则标签;
提升::精神::气::规则开始;
};
测试代码:
void doTestParser2()
{
for
(
auto& input : std::list<std::string>
{
"{ \"68965363-2d87-46d4-b05d-f293f2c8403b\", 0, 1583798400000000, 86400000000, 600000000, { } };",
"{ \"68965363-2d87-46d4-b05d-f293f2c8403b\", 0, 1583798400000000, 86400000000, 600000000, { { \"motorbike\", 5 } } };",
"{ \"68965363-2d87-46d4-b05d-f293f2c8403b\", 0, 1583798400000000, 86400000000, 600000000, { { \"motorbike\", 5 }, { \"aeroplane\", 6 } } };"
}
)
{
using namespace boost::spirit;
auto f(std::begin(input)), l(std::end(input));
load_parser<decltype(f)> p;
try
{
BulkDataParmas result { };
std::string sresult { };
bool ok = qi::phrase_parse(f, l, p > ';', qi::ascii::space, result);
if (!ok)
std::cerr << "invalid input" << std::endl;
else
{
std::cout << "ok: " << input << std::endl;
std::cout << "UUID: " << result.strUUID << std::endl;
std::cout << "subcam: " << result.subcam << std::endl;
std::cout << "pts_beg: " << result.pts_beg << std::endl;
std::cout << "pts_len: " << result.pts_len << std::endl;
std::cout << "pts_gap: " << result.pts_gap << std::endl;
for (auto const& tup : result.labels)
{
std::cout << "label: " << std::get<0>(tup) << std::endl;
std::cout << "level: " << std::get<1>(tup) << std::endl;
}
}
}
catch (const qi::expectation_failure<decltype(f)>& e)
{
std::cerr << "expectation_failure at '" << std::string(e.first, e.last) << "'\n";
}
}
}
void doTestParser2()
{
对于
(
自动输入(&I):标准::列表
{
“{68965363-2d87-46d4-b05d-f293f2c8403b\”,01583798400000000086400000000600000000,{};”,
“{68965363-2d87-46d4-b05d-f293f2c8403b\”,01583798400000000086400000000600000000,{{“摩托车”,5}}};“,
“{68965363-2d87-46d4-b05d-f293f2c8403b\”,0158379400000086400000000600000000,{{{“摩托车”,5},{“飞机”,6};”
}
)
{
使用名称空间boost::spirit;
自动f(标准::开始(输入)),l(标准::结束(输入));
加载语法分析器p;
尝试
{
BulkDataParmas结果{};
std::string sresult{};
bool ok=qi::短语解析(f,l,p>“;”,qi::ascii::空格,结果);
如果(!ok)
除了你提到的两件事(正确的),我建议
一些简化:
uuid = '"' >> qi::raw [
hex_<4>{} >> qi::repeat(3)['-' >> hex_<2>{}] >> '-' >> hex_<6>{}
] >> '"';
在这里,我建议使用*
来接受空字符串(这通常是
引用字符串的“点”,因此我们可以明确表示embdeded
空白或有意为空字符串)。此外,使用~charset
可以
效率更高
还删除了lexeme[]
,因为该规则已在没有跳过程序的情况下声明
结束:
label = '{' >> quoted_string >> ',' >> qi::int_ >> '}';
start = qi::skip(ascii::space) [ '{'
>> uuid >> ','
>> qi::auto_ >> ','
>> qi::auto_ >> ','
>> qi::auto_ >> ','
>> qi::auto_ >> ','
>> '{' >> -(label % ',') >> '}'
>> '}' >> ';'
];
请注意,我加入了skipper选项。因此,您不必在短语\u parse
中繁琐地传递正确的内容。skipper通常不是调用者无论如何都应该能够更改的东西
现在,让我们也对改编进行现代化:
BOOST_FUSION_ADAPT_STRUCT(BulkDataParams, strUUID, subcam, pts_beg, pts_len, pts_gap, labels)
在此之后,您可以以现代方式重新销售类型,而不必冒任何兼容性问题的风险。请注意,这也是您选择在那里的开始规则中使用qi::auto \
的原因,因此,当解析器结果以预期方式隐式转换为目标类型时,您不会感到痛苦的意外
struct BulkDataParams {
std::string strUUID;
int16_t subcam;
int64_t pts_beg;
int64_t pts_len;
int64_t pts_gap;
label_t labels;
};
现在,让我们加入调试输出和测试主体:
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <iostream>
#include <iomanip>
using label_t = std::vector<std::tuple<std::string, int>>;
namespace std {
std::ostream& operator<<(std::ostream& os, label_t::value_type const& t) {
auto const& [k,v] = t;
return os << "[" << std::quoted(k) << "," << v << "]";
}
std::ostream& operator<<(std::ostream& os, label_t const& m) {
os << "{";
for (auto&& el:m) os << el << ",";
return os << "}";
}
}
struct BulkDataParams {
std::string strUUID;
int16_t subcam;
int64_t pts_beg;
int64_t pts_len;
int64_t pts_gap;
label_t labels;
};
BOOST_FUSION_ADAPT_STRUCT(BulkDataParams, strUUID, subcam, pts_beg, pts_len, pts_gap, labels)
template <typename Iterator> struct load_parser : boost::spirit::qi::grammar<Iterator, BulkDataParams()> {
load_parser() : load_parser::base_type(start) {
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
uuid = '"' >> qi::raw [
hex_<4>{} >> qi::repeat(3)['-' >> hex_<2>{}] >> '-' >> hex_<6>{}
] >> '"';
quoted_string = '"' >> *~qi::char_('"') >> '"';
label = '{' >> quoted_string >> ',' >> qi::int_ >> '}';
start = qi::skip(ascii::space) [ '{'
>> uuid >> ','
>> qi::auto_ >> ','
>> qi::auto_ >> ','
>> qi::auto_ >> ','
>> qi::auto_ >> ','
>> '{' >> -(label % ',') >> '}'
>> '}' >> ';'
];
BOOST_SPIRIT_DEBUG_NODES(
(uuid) (quoted_string) (label) (start)
)
}
template<int N> using hex_ = boost::spirit::qi::int_parser<std::intmax_t, 16, 2*N, 2*N>;
private:
boost::spirit::qi::rule<Iterator, std::string()> uuid;
boost::spirit::qi::rule<Iterator, std::string()> quoted_string;
boost::spirit::qi::rule<Iterator, label_t::value_type(), boost::spirit::ascii::space_type> label;
boost::spirit::qi::rule<Iterator, BulkDataParams()> start;
};
int main() {
for (std::string const input : {
R"({ "68965363-2d87-46d4-b05d-f293f2c8403b", 0, 1583798400000000, 86400000000, 600000000, { { "motorbike", 5 }, { "aeroplane", 6 } } };)",
})
{
auto f = begin(input), l = end(input);
BulkDataParams bdp;
load_parser<std::string::const_iterator> p;
if (parse(f, l, p, bdp)) {
std::cout << "Parsed: " << boost::fusion::as_vector(bdp) << "\n";
} else {
std::cout << "Parse Failed\n";
}
if (f != l) {
std::cout << "Remaining unparsed: " << std::quoted(std::string(f,l)) << "\n";
}
}
}
如何生成调试输出?它是完整列表中的#define BOOST\u SPIRIT\u debug
。在这种情况下,我偷偷地使用了一些操作符
BOOST_FUSION_ADAPT_STRUCT(BulkDataParams, strUUID, subcam, pts_beg, pts_len, pts_gap, labels)
struct BulkDataParams {
std::string strUUID;
int16_t subcam;
int64_t pts_beg;
int64_t pts_len;
int64_t pts_gap;
label_t labels;
};
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <iostream>
#include <iomanip>
using label_t = std::vector<std::tuple<std::string, int>>;
namespace std {
std::ostream& operator<<(std::ostream& os, label_t::value_type const& t) {
auto const& [k,v] = t;
return os << "[" << std::quoted(k) << "," << v << "]";
}
std::ostream& operator<<(std::ostream& os, label_t const& m) {
os << "{";
for (auto&& el:m) os << el << ",";
return os << "}";
}
}
struct BulkDataParams {
std::string strUUID;
int16_t subcam;
int64_t pts_beg;
int64_t pts_len;
int64_t pts_gap;
label_t labels;
};
BOOST_FUSION_ADAPT_STRUCT(BulkDataParams, strUUID, subcam, pts_beg, pts_len, pts_gap, labels)
template <typename Iterator> struct load_parser : boost::spirit::qi::grammar<Iterator, BulkDataParams()> {
load_parser() : load_parser::base_type(start) {
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
uuid = '"' >> qi::raw [
hex_<4>{} >> qi::repeat(3)['-' >> hex_<2>{}] >> '-' >> hex_<6>{}
] >> '"';
quoted_string = '"' >> *~qi::char_('"') >> '"';
label = '{' >> quoted_string >> ',' >> qi::int_ >> '}';
start = qi::skip(ascii::space) [ '{'
>> uuid >> ','
>> qi::auto_ >> ','
>> qi::auto_ >> ','
>> qi::auto_ >> ','
>> qi::auto_ >> ','
>> '{' >> -(label % ',') >> '}'
>> '}' >> ';'
];
BOOST_SPIRIT_DEBUG_NODES(
(uuid) (quoted_string) (label) (start)
)
}
template<int N> using hex_ = boost::spirit::qi::int_parser<std::intmax_t, 16, 2*N, 2*N>;
private:
boost::spirit::qi::rule<Iterator, std::string()> uuid;
boost::spirit::qi::rule<Iterator, std::string()> quoted_string;
boost::spirit::qi::rule<Iterator, label_t::value_type(), boost::spirit::ascii::space_type> label;
boost::spirit::qi::rule<Iterator, BulkDataParams()> start;
};
int main() {
for (std::string const input : {
R"({ "68965363-2d87-46d4-b05d-f293f2c8403b", 0, 1583798400000000, 86400000000, 600000000, { { "motorbike", 5 }, { "aeroplane", 6 } } };)",
})
{
auto f = begin(input), l = end(input);
BulkDataParams bdp;
load_parser<std::string::const_iterator> p;
if (parse(f, l, p, bdp)) {
std::cout << "Parsed: " << boost::fusion::as_vector(bdp) << "\n";
} else {
std::cout << "Parse Failed\n";
}
if (f != l) {
std::cout << "Remaining unparsed: " << std::quoted(std::string(f,l)) << "\n";
}
}
}
<start>
<try>{ "68965363-2d87-46d</try>
<uuid>
<try>"68965363-2d87-46d4-</try>
<success>, 0, 158379840000000</success>
<attributes>[[6, 8, 9, 6, 5, 3, 6, 3, -, 2, d, 8, 7, -, 4, 6, d, 4, -, b, 0, 5, d, -, f, 2, 9, 3, f, 2, c, 8, 4, 0, 3, b]]</attributes>
</uuid>
<label>
<try> { "motorbike", 5 },</try>
<quoted_string>
<try>"motorbike", 5 }, { </try>
<success>, 5 }, { "aeroplane"</success>
<attributes>[[m, o, t, o, r, b, i, k, e]]</attributes>
</quoted_string>
<success>, { "aeroplane", 6 }</success>
<attributes>[[[m, o, t, o, r, b, i, k, e], 5]]</attributes>
</label>
<label>
<try> { "aeroplane", 6 } </try>
<quoted_string>
<try>"aeroplane", 6 } } }</try>
<success>, 6 } } };</success>
<attributes>[[a, e, r, o, p, l, a, n, e]]</attributes>
</quoted_string>
<success> } };</success>
<attributes>[[[a, e, r, o, p, l, a, n, e], 6]]</attributes>
</label>
<success></success>
<attributes>[[[6, 8, 9, 6, 5, 3, 6, 3, -, 2, d, 8, 7, -, 4, 6, d, 4, -, b, 0, 5, d, -, f, 2, 9, 3, f, 2, c, 8, 4, 0, 3, b], 0, 1583798400000000, 86400000000, 600000000, [[[m, o, t, o, r, b, i, k, e], 5], [[a, e, r, o, p, l, a, n, e], 6]]]]</attributes>
</start>