如何使用 boost spirit 将字符串解析为元组向量?
How to parse a string into vector of tuples with boost spirit?
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <string>
#include <iostream>
#include <tuple>
#include <vector>
using tpl = std::tuple<int, double, std::string>;
boost::spirit::qi::rule<std::string::iterator, tpl> parse_into_tuple =
boost::spirit::qi::int_ >> ',' >>
boost::spirit::qi::double_ >> ',' >>
boost::spirit::lexeme[+boost::spirit::qi::char_ - ';'];
boost::spirit::qi::rule<std::string::iterator, std::vector<tpl>>
parse_into_vec = parse_into_tuple % ';';
int main()
{
std::string s = "1,5.4,abc xyz;2,91.05,qwe jkl";
std::vector<tpl> v;
bool b = boost::spirit::qi::parse(
s.begin(), s.end(), parse_into_vec, v, boost::spirit::qi::space);
std::cout << std::boolalpha << b << '\n';
std::cout << v.size() << '\n';
for(const auto& t: v)
{
std::cout << std::get<0>(t) << ", " << std::get<1>(t) << ", " << std::get<2>(t) << '\n';
}
}
现在的输出是 "true" 和 0(向量的大小)。
我的预期输出是 2 号。
此外,如果我使用 phrase_parse 而不是解析,它不会编译。我的错误是什么以及如何达到预期的结果?
从解析调用中省略 boost::spirit::qi::space
,您没有 space 作为分隔符。
您也可以删除 lexeme[]
指令,因为您不使用跳过进行解析。
phrase_parse
要求规则具有兼容的 Skipper
,而您没有
修复规则定义以将属性签名正确定义为 tpl()
而不是 tpl
:
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
using tpl = std::tuple<int, double, std::string>;
boost::spirit::qi::rule<std::string::iterator, tpl()> parse_into_tuple =
boost::spirit::qi::int_ >> ',' >> boost::spirit::qi::double_ >> ',' >>
boost::spirit::lexeme[+boost::spirit::qi::char_ - ';'];
boost::spirit::qi::rule<std::string::iterator, std::vector<tpl>() > parse_into_vec = parse_into_tuple % ';';
int main() {
std::string s = "1,5.4,abc xyz;2,91.05,qwe jkl";
std::vector<tpl> v;
bool b = boost::spirit::qi::parse(s.begin(), s.end(), parse_into_vec, v);
std::cout << std::boolalpha << b << '\n';
std::cout << v.size() << '\n';
for (const auto &t : v) {
std::cout << std::get<0>(t) << ", " << std::get<1>(t) << ", " << std::get<2>(t) << '\n';
}
}
版画
true
1
1, 5.4, abc xyz;2,91.05,qwe jkl
奖金
- 解决了 white-space 以您可能预期的方式跳过的问题(参见 Boost spirit skipper issues)
- 在语法中隐藏船长选择
- 添加调试支持
- 简化调试输出
- 错误检查(也考虑 grammar/parse 表达式中的
>> qi::eoi
)
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
using tpl = std::tuple<int, double, std::string>;
using tpls = std::vector<tpl>;
template <typename It = std::string::const_iterator>
struct grammar : qi::grammar<It, tpls()> {
grammar() : grammar::base_type(start) {
using namespace qi;
tuple_ = int_ >> ',' >> double_ >> ',' >> lexeme[+~char_(';')];
vec_ = tuple_ % ';';
start = skip(space) [ vec_ ];
BOOST_SPIRIT_DEBUG_NODES((start)(vec_)(tuple_))
}
private:
qi::rule<It, tpls()> start;
using Skipper = qi::space_type;
qi::rule<It, tpls(), Skipper> vec_;
qi::rule<It, tpl(), Skipper> tuple_;
};
int main() {
grammar<> const g;
for(std::string const s : {
"1,5.4,abc xyz;2,91.05,qwe jkl",
"1,5.4,abc xyz;2,91.05,qwe jkl; trailing garbage",
"1, \n5.4, abc xyz;",
})
{
auto f = s.begin(), l = s.end();
std::vector<tpl> v;
if (parse(f, l, g, v))
{
std::cout << v.size() << '\n';
for (const auto &t : v) {
std::cout << boost::fusion::as_vector(t) << "\n";
}
} else {
std::cout << "Parse failed\n";
}
if (f!=l) {
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
}
版画
2
(1 5.4 abc xyz)
(2 91.05 qwe jkl)
2
(1 5.4 abc xyz)
(2 91.05 qwe jkl)
Remaining unparsed: '; trailing garbage'
1
(1 5.4 abc xyz)
Remaining unparsed: ';'
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <string>
#include <iostream>
#include <tuple>
#include <vector>
using tpl = std::tuple<int, double, std::string>;
boost::spirit::qi::rule<std::string::iterator, tpl> parse_into_tuple =
boost::spirit::qi::int_ >> ',' >>
boost::spirit::qi::double_ >> ',' >>
boost::spirit::lexeme[+boost::spirit::qi::char_ - ';'];
boost::spirit::qi::rule<std::string::iterator, std::vector<tpl>>
parse_into_vec = parse_into_tuple % ';';
int main()
{
std::string s = "1,5.4,abc xyz;2,91.05,qwe jkl";
std::vector<tpl> v;
bool b = boost::spirit::qi::parse(
s.begin(), s.end(), parse_into_vec, v, boost::spirit::qi::space);
std::cout << std::boolalpha << b << '\n';
std::cout << v.size() << '\n';
for(const auto& t: v)
{
std::cout << std::get<0>(t) << ", " << std::get<1>(t) << ", " << std::get<2>(t) << '\n';
}
}
现在的输出是 "true" 和 0(向量的大小)。 我的预期输出是 2 号。 此外,如果我使用 phrase_parse 而不是解析,它不会编译。我的错误是什么以及如何达到预期的结果?
从解析调用中省略 boost::spirit::qi::space
,您没有 space 作为分隔符。
您也可以删除 lexeme[]
指令,因为您不使用跳过进行解析。
phrase_parse
要求规则具有兼容的 Skipper
,而您没有
修复规则定义以将属性签名正确定义为 tpl()
而不是 tpl
:
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
using tpl = std::tuple<int, double, std::string>;
boost::spirit::qi::rule<std::string::iterator, tpl()> parse_into_tuple =
boost::spirit::qi::int_ >> ',' >> boost::spirit::qi::double_ >> ',' >>
boost::spirit::lexeme[+boost::spirit::qi::char_ - ';'];
boost::spirit::qi::rule<std::string::iterator, std::vector<tpl>() > parse_into_vec = parse_into_tuple % ';';
int main() {
std::string s = "1,5.4,abc xyz;2,91.05,qwe jkl";
std::vector<tpl> v;
bool b = boost::spirit::qi::parse(s.begin(), s.end(), parse_into_vec, v);
std::cout << std::boolalpha << b << '\n';
std::cout << v.size() << '\n';
for (const auto &t : v) {
std::cout << std::get<0>(t) << ", " << std::get<1>(t) << ", " << std::get<2>(t) << '\n';
}
}
版画
true
1
1, 5.4, abc xyz;2,91.05,qwe jkl
奖金
- 解决了 white-space 以您可能预期的方式跳过的问题(参见 Boost spirit skipper issues)
- 在语法中隐藏船长选择
- 添加调试支持
- 简化调试输出
- 错误检查(也考虑 grammar/parse 表达式中的
>> qi::eoi
)
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
using tpl = std::tuple<int, double, std::string>;
using tpls = std::vector<tpl>;
template <typename It = std::string::const_iterator>
struct grammar : qi::grammar<It, tpls()> {
grammar() : grammar::base_type(start) {
using namespace qi;
tuple_ = int_ >> ',' >> double_ >> ',' >> lexeme[+~char_(';')];
vec_ = tuple_ % ';';
start = skip(space) [ vec_ ];
BOOST_SPIRIT_DEBUG_NODES((start)(vec_)(tuple_))
}
private:
qi::rule<It, tpls()> start;
using Skipper = qi::space_type;
qi::rule<It, tpls(), Skipper> vec_;
qi::rule<It, tpl(), Skipper> tuple_;
};
int main() {
grammar<> const g;
for(std::string const s : {
"1,5.4,abc xyz;2,91.05,qwe jkl",
"1,5.4,abc xyz;2,91.05,qwe jkl; trailing garbage",
"1, \n5.4, abc xyz;",
})
{
auto f = s.begin(), l = s.end();
std::vector<tpl> v;
if (parse(f, l, g, v))
{
std::cout << v.size() << '\n';
for (const auto &t : v) {
std::cout << boost::fusion::as_vector(t) << "\n";
}
} else {
std::cout << "Parse failed\n";
}
if (f!=l) {
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
}
版画
2
(1 5.4 abc xyz)
(2 91.05 qwe jkl)
2
(1 5.4 abc xyz)
(2 91.05 qwe jkl)
Remaining unparsed: '; trailing garbage'
1
(1 5.4 abc xyz)
Remaining unparsed: ';'