C++ boost::qi 将 space 和换行符分隔的数字解析为二维向量
C++ boost::qi parse space and newline delimited numbers as a 2D vector
我有多个浮点数行,一行中的数字被 space 分隔开
例如
1.2 2.2 3.2
1.1 2.1 3.1
我想将上述数字提取为字符串并解析为二维向量;
std::vector< std::vector< std::string > > { {"1.2", "2.2", "3.2"},{"1.1", "2.1", "3.1} }
我的代码如下。
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <string>
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
using VecType = std::vector< std::vector< std::string >>;
struct employee
{
VecType name;
};
}
BOOST_FUSION_ADAPT_STRUCT(
client::employee,
(client::VecType, name)
)
//]
namespace client
{
template <typename Iterator>
struct employee_parser : qi::grammar<Iterator, VecType(), ascii::space_type>
{
employee_parser() : employee_parser::base_type(start)
{
using qi::lexeme;
using ascii::char_;
number %= lexeme[+char_( "0-9." ) >> qi::space ];
start %= +number;
}
qi::rule<Iterator, std::string(), ascii::space_type> number;
qi::rule<Iterator, VecType(), ascii::space_type> start;
};
}
但这会产生 2D 向量,其外部 vec 大小为 6,每个内部向量大小为 1。
我不明白如何从新行中拆分字符串只生成 2 个内部向量。
你要拆分规则。让我们从类型开始:
using VecType = std::vector<std::string>;
using VecVecType = std::vector<VecType>;
现在,让我们制定一个规则来解析一个数字,一行数字和多行:
qi::rule<Iterator, std::string()> number;
qi::rule<Iterator, VecType(), qi::blank_type> row;
qi::rule<Iterator, VecVecType()> start;
实现它们(请注意,我将 skipper 移到了语法中,因为将它泄漏到界面中不是一个好主意):
number = raw [ double_ ]; // raw[] to get string value
row = +number;
start = qi::skip(blank) [ row % eol ];
注意:我使用 blank
而不是 space
因为我们不想跳过对语法很重要的 eol
。
演示
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iomanip>
namespace client {
namespace qi = boost::spirit::qi;
using VecType = std::vector<std::string>;
using VecVecType = std::vector<VecType>;
} // namespace client
namespace client {
template <typename Iterator>
struct my_parser : qi::grammar<Iterator, VecVecType()> {
my_parser() : my_parser::base_type(start) {
using namespace qi;
number = raw [ double_ ]; // raw[] to get string value
row = *number;
start = qi::skip(blank) [ row % eol ];
}
qi::rule<Iterator, std::string()> number;
qi::rule<Iterator, VecType(), qi::blank_type> row;
qi::rule<Iterator, VecVecType()> start;
};
} // namespace client
int main() {
client::my_parser<std::string::const_iterator> const p;
for (std::string const& input: {
"",
"1.2 2.2 3.2\n1.1 2.1 3.1",
})
{
std::cout << "--- " << std::quoted(input) << " -----\n";
auto f = begin(input), l = end(input);
client::VecVecType output;
if (parse(f, l, p, output)) {
std::cout << "Parsed:\n";
for (auto& row : output) {
for (auto& v : row) {
std::cout << "\t" << v;
}
std::cout << "\n";
}
} else {
std::cout << "Failed\n";
}
if (f!=l) {
std::cout << "Remaining input: " << std::quoted(std::string(f,l)) << "\n";
}
}
}
版画
--- "" -----
Parsed:
--- "1.2 2.2 3.2
1.1 2.1 3.1" -----
Parsed:
1.2 2.2 3.2
1.1 2.1 3.1
奖金
强类型让一切变得更有趣:如果可以解析成双精度数,为什么还要解析成字符串?
还展示了如何启用规则调试:
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iomanip>
namespace client {
namespace qi = boost::spirit::qi;
using VecType = std::vector<double>;
using VecVecType = std::vector<VecType>;
} // namespace client
namespace client {
template <typename Iterator>
struct my_parser : qi::grammar<Iterator, VecVecType()> {
my_parser() : my_parser::base_type(start) {
using namespace qi;
row = *double_;
start = qi::skip(blank) [ row % eol ];
BOOST_SPIRIT_DEBUG_NODES((start)(row))
}
private:
qi::rule<Iterator, VecType(), qi::blank_type> row;
qi::rule<Iterator, VecVecType()> start;
};
} // namespace client
int main() {
client::my_parser<std::string::const_iterator> const p;
for (std::string const& input: {
"",
"1.2 2.2 3.2\n1.1 2.1 3.1",
})
{
std::cout << "--- " << std::quoted(input) << " -----\n";
auto f = begin(input), l = end(input);
client::VecVecType output;
if (parse(f, l, p, output)) {
std::cout << "Parsed:\n";
for (auto& row : output) {
for (auto& v : row) {
std::cout << "\t" << v;
}
std::cout << "\n";
}
} else {
std::cout << "Failed\n";
}
if (f!=l) {
std::cout << "Remaining input: " << std::quoted(std::string(f,l)) << "\n";
}
}
}
版画
--- "" -----
<start>
<try></try>
<row>
<try></try>
<success></success>
<attributes>[[]]</attributes>
</row>
<success></success>
<attributes>[[[]]]</attributes>
</start>
Parsed:
--- "1.2 2.2 3.2
1.1 2.1 3.1" -----
<start>
<try>1.2 2.2 3.2\n1.1 2.1 </try>
<row>
<try>1.2 2.2 3.2\n1.1 2.1 </try>
<success>\n1.1 2.1 3.1</success>
<attributes>[[1.2, 2.2, 3.2]]</attributes>
</row>
<row>
<try>1.1 2.1 3.1</try>
<success></success>
<attributes>[[1.1, 2.1, 3.1]]</attributes>
</row>
<success></success>
<attributes>[[[1.2, 2.2, 3.2], [1.1, 2.1, 3.1]]]</attributes>
</start>
Parsed:
1.2 2.2 3.2
1.1 2.1 3.1
我有多个浮点数行,一行中的数字被 space 分隔开 例如
1.2 2.2 3.2
1.1 2.1 3.1
我想将上述数字提取为字符串并解析为二维向量;
std::vector< std::vector< std::string > > { {"1.2", "2.2", "3.2"},{"1.1", "2.1", "3.1} }
我的代码如下。
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <string>
namespace client
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
using VecType = std::vector< std::vector< std::string >>;
struct employee
{
VecType name;
};
}
BOOST_FUSION_ADAPT_STRUCT(
client::employee,
(client::VecType, name)
)
//]
namespace client
{
template <typename Iterator>
struct employee_parser : qi::grammar<Iterator, VecType(), ascii::space_type>
{
employee_parser() : employee_parser::base_type(start)
{
using qi::lexeme;
using ascii::char_;
number %= lexeme[+char_( "0-9." ) >> qi::space ];
start %= +number;
}
qi::rule<Iterator, std::string(), ascii::space_type> number;
qi::rule<Iterator, VecType(), ascii::space_type> start;
};
}
但这会产生 2D 向量,其外部 vec 大小为 6,每个内部向量大小为 1。
我不明白如何从新行中拆分字符串只生成 2 个内部向量。
你要拆分规则。让我们从类型开始:
using VecType = std::vector<std::string>;
using VecVecType = std::vector<VecType>;
现在,让我们制定一个规则来解析一个数字,一行数字和多行:
qi::rule<Iterator, std::string()> number;
qi::rule<Iterator, VecType(), qi::blank_type> row;
qi::rule<Iterator, VecVecType()> start;
实现它们(请注意,我将 skipper 移到了语法中,因为将它泄漏到界面中不是一个好主意):
number = raw [ double_ ]; // raw[] to get string value
row = +number;
start = qi::skip(blank) [ row % eol ];
注意:我使用 blank
而不是 space
因为我们不想跳过对语法很重要的 eol
。
演示
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iomanip>
namespace client {
namespace qi = boost::spirit::qi;
using VecType = std::vector<std::string>;
using VecVecType = std::vector<VecType>;
} // namespace client
namespace client {
template <typename Iterator>
struct my_parser : qi::grammar<Iterator, VecVecType()> {
my_parser() : my_parser::base_type(start) {
using namespace qi;
number = raw [ double_ ]; // raw[] to get string value
row = *number;
start = qi::skip(blank) [ row % eol ];
}
qi::rule<Iterator, std::string()> number;
qi::rule<Iterator, VecType(), qi::blank_type> row;
qi::rule<Iterator, VecVecType()> start;
};
} // namespace client
int main() {
client::my_parser<std::string::const_iterator> const p;
for (std::string const& input: {
"",
"1.2 2.2 3.2\n1.1 2.1 3.1",
})
{
std::cout << "--- " << std::quoted(input) << " -----\n";
auto f = begin(input), l = end(input);
client::VecVecType output;
if (parse(f, l, p, output)) {
std::cout << "Parsed:\n";
for (auto& row : output) {
for (auto& v : row) {
std::cout << "\t" << v;
}
std::cout << "\n";
}
} else {
std::cout << "Failed\n";
}
if (f!=l) {
std::cout << "Remaining input: " << std::quoted(std::string(f,l)) << "\n";
}
}
}
版画
--- "" -----
Parsed:
--- "1.2 2.2 3.2
1.1 2.1 3.1" -----
Parsed:
1.2 2.2 3.2
1.1 2.1 3.1
奖金
强类型让一切变得更有趣:如果可以解析成双精度数,为什么还要解析成字符串?
还展示了如何启用规则调试:
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iomanip>
namespace client {
namespace qi = boost::spirit::qi;
using VecType = std::vector<double>;
using VecVecType = std::vector<VecType>;
} // namespace client
namespace client {
template <typename Iterator>
struct my_parser : qi::grammar<Iterator, VecVecType()> {
my_parser() : my_parser::base_type(start) {
using namespace qi;
row = *double_;
start = qi::skip(blank) [ row % eol ];
BOOST_SPIRIT_DEBUG_NODES((start)(row))
}
private:
qi::rule<Iterator, VecType(), qi::blank_type> row;
qi::rule<Iterator, VecVecType()> start;
};
} // namespace client
int main() {
client::my_parser<std::string::const_iterator> const p;
for (std::string const& input: {
"",
"1.2 2.2 3.2\n1.1 2.1 3.1",
})
{
std::cout << "--- " << std::quoted(input) << " -----\n";
auto f = begin(input), l = end(input);
client::VecVecType output;
if (parse(f, l, p, output)) {
std::cout << "Parsed:\n";
for (auto& row : output) {
for (auto& v : row) {
std::cout << "\t" << v;
}
std::cout << "\n";
}
} else {
std::cout << "Failed\n";
}
if (f!=l) {
std::cout << "Remaining input: " << std::quoted(std::string(f,l)) << "\n";
}
}
}
版画
--- "" -----
<start>
<try></try>
<row>
<try></try>
<success></success>
<attributes>[[]]</attributes>
</row>
<success></success>
<attributes>[[[]]]</attributes>
</start>
Parsed:
--- "1.2 2.2 3.2
1.1 2.1 3.1" -----
<start>
<try>1.2 2.2 3.2\n1.1 2.1 </try>
<row>
<try>1.2 2.2 3.2\n1.1 2.1 </try>
<success>\n1.1 2.1 3.1</success>
<attributes>[[1.2, 2.2, 3.2]]</attributes>
</row>
<row>
<try>1.1 2.1 3.1</try>
<success></success>
<attributes>[[1.1, 2.1, 3.1]]</attributes>
</row>
<success></success>
<attributes>[[[1.2, 2.2, 3.2], [1.1, 2.1, 3.1]]]</attributes>
</start>
Parsed:
1.2 2.2 3.2
1.1 2.1 3.1