boost::spirit::x3 phrase_parse 在推入向量之前进行算术运算
boost::spirit::x3 phrase_parse doing arithmetic operations before pushing into vector
我正在为我的大学学习做一个项目。我的目标是将大文件 (2.6 GB) 中的双精度数字读取到双精度向量中。
我正在使用带有 mmap 的 boost spirit x3 库。我在网上找到了一些代码:我正在使用的https://github.com/sehe/bench_float_parsing。
在将这些双精度值推入向量之前,我想对它们进行一些算术运算。所以我被困在这里了。在推送值之前,我如何进行一些算术运算以将值加倍?
template <typename source_it>
size_t x3_phrase_parse<data::float_vector, source_it>::parse(source_it f, source_it l, data::float_vector& data) const {
using namespace x3;
bool ok = phrase_parse(f, l, *double_ % eol, space, data);
if (ok)
std::cout << "parse success\n";
else
std::cerr << "parse failed: '" << std::string(f, l) << "'\n";
if (f != l) std::cerr << "trailing unparsed: '" << std::string(f, l) << "'\n";
std::cout << "data.size(): " << data.size() << "\n";
return data.size();
}
很抱歉没有准确回答您的问题。但提升精神不是合适的工具。 Spirit 是一个解析器生成器(作为一个子集,当然也进行词法分析)。因此,在乔姆斯基的语言层次结构中更上一层楼。您不需要解析器,而是正则表达式:std:regex
可以使用正则表达式轻松找到双精度值。在附带的代码中,我为双打创建了一个简单的模式。并且可以使用正则表达式来搜索它。
因此,我们将从 istream 中读取(可以是文件、字符串流、控制台输入或其他任何内容)。我们将逐行读取,直到消耗完整个输入。
对于每一行,我们将检查输入是否与预期模式匹配,是否为 1 double。
然后我们读这个double,做一些计算然后把它压入vector。
请看下面非常简单的代码。
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <regex>
std::istringstream input{R"(0.0
1.5
2.0
3.0
4.0
-5.0
)"};
using VectorDouble = std::vector<double>;
const std::regex reDouble{R"(([-+]?[0-9]*\.?[0-9]*))"};
std::istream& get(std::istream& is, VectorDouble& dd)
{
// Reset vector to empty before reading
dd.clear();
//Read all data from istream
std::string line{};
while (getline(is, line)) {
// Search for 2 doubles
std::smatch sm;
if (std::regex_search(line, sm, reDouble)) {
// Convert found strings to double
double d1{std::stod(sm[1])};
// Do some calculations
d1 = d1 + 10.0;
// Push back into vector
dd.emplace_back(d1);
}
else
std::cerr << "Error found in line: " << line << "\n";
}
return is;
}
int main()
{
// Define vector and fill it
VectorDouble dd{};
(void)get(input, dd);
// Some debug output
for (double& d : dd) {
std::cout << d << "\n";
}
return 0;
}
为什么不用semantic actions来进行算术运算?
在下面的代码中:
#include <iostream>
#include <sstream>
#include <string>
#include <cstdio>
#include <vector>
using VectorDouble = std::vector<double>;
void show( VectorDouble const& dd)
{
std::cout<<"vector result=\n";
for (double const& d : dd) {
std::cout << d << "\n";
}
}
auto arith_ops=[](double&x){ x+=10.0;};
std::string input_err_yes{R"(0.0
1.5
2.0xxx
not double
4.0
-5.0
)"};
std::string input_err_not{R"(0.0
1.5
2.0
3.0
4.0
-5.0
)"};
void stod_error_recov(std::string const&input)
//Use this for graceful error recovery in case input has syntax errors.
{
std::cout<<__func__<<":\n";
VectorDouble dd;
std::istringstream is(input);
std::string line{};
while (getline(is, line) ) {
try {
std::size_t eod;
double d1(std::stod(line,&eod));
arith_ops(d1);
dd.emplace_back(d1);
auto const eol=line.size();
if(eod!=eol) {
std::cerr << "Warning: trailing chars after double in line: "<< line << "\n";
}
}
catch (const std::invalid_argument&) {
if(!is.eof())
std::cerr << "Error: found in line: " << line << "\n";
}
}
show(dd);
}
void stod_error_break(std::string const&input)
//Use this if input is sure to have correct syntax.
{
std::cout<<__func__<<":\n";
VectorDouble dd;
char const*d=input.data();
while(true) {
try {
std::size_t eod;
double d1(std::stod(d,&eod));
d+=eod;
arith_ops(d1);
dd.emplace_back(d1);
}
catch (const std::invalid_argument&) {
//Either syntax error
//Or end of input.
break;
}
}
show(dd);
}
#include <boost/spirit/home/x3.hpp>
void x3_error_break(std::string const&input)
//boost::spirit::x3 method.
{
std::cout<<__func__<<":\n";
VectorDouble dd;
auto f=input.begin();
auto l=input.end();
using namespace boost::spirit::x3;
auto arith_action=[](auto&ctx)
{ arith_ops(_attr(ctx));
};
phrase_parse(f, l, double_[arith_action] % eol, blank, dd);
show(dd);
}
int main()
{
//stod_error_recov(input_err_yes);
//stod_error_break(input_err_not);
x3_error_break(input_err_not);
return 0;
}
stod_* 函数与 Armin 的不同,不需要 regex
因为
std:stod 进行解析,因为它不
使用 regex
它可能运行得更快一些。
有 2 个带有源代码注释的 stod_* 函数
指出应该使用哪个。
为了完整起见,使用 boost::spirit::x3 的第三个函数是
显示。恕我直言,它的可读性比其他的要好;然而,
编译可能需要更多时间。
我正在为我的大学学习做一个项目。我的目标是将大文件 (2.6 GB) 中的双精度数字读取到双精度向量中。
我正在使用带有 mmap 的 boost spirit x3 库。我在网上找到了一些代码:我正在使用的https://github.com/sehe/bench_float_parsing。
在将这些双精度值推入向量之前,我想对它们进行一些算术运算。所以我被困在这里了。在推送值之前,我如何进行一些算术运算以将值加倍?
template <typename source_it>
size_t x3_phrase_parse<data::float_vector, source_it>::parse(source_it f, source_it l, data::float_vector& data) const {
using namespace x3;
bool ok = phrase_parse(f, l, *double_ % eol, space, data);
if (ok)
std::cout << "parse success\n";
else
std::cerr << "parse failed: '" << std::string(f, l) << "'\n";
if (f != l) std::cerr << "trailing unparsed: '" << std::string(f, l) << "'\n";
std::cout << "data.size(): " << data.size() << "\n";
return data.size();
}
很抱歉没有准确回答您的问题。但提升精神不是合适的工具。 Spirit 是一个解析器生成器(作为一个子集,当然也进行词法分析)。因此,在乔姆斯基的语言层次结构中更上一层楼。您不需要解析器,而是正则表达式:std:regex
可以使用正则表达式轻松找到双精度值。在附带的代码中,我为双打创建了一个简单的模式。并且可以使用正则表达式来搜索它。
因此,我们将从 istream 中读取(可以是文件、字符串流、控制台输入或其他任何内容)。我们将逐行读取,直到消耗完整个输入。
对于每一行,我们将检查输入是否与预期模式匹配,是否为 1 double。
然后我们读这个double,做一些计算然后把它压入vector。
请看下面非常简单的代码。
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <regex>
std::istringstream input{R"(0.0
1.5
2.0
3.0
4.0
-5.0
)"};
using VectorDouble = std::vector<double>;
const std::regex reDouble{R"(([-+]?[0-9]*\.?[0-9]*))"};
std::istream& get(std::istream& is, VectorDouble& dd)
{
// Reset vector to empty before reading
dd.clear();
//Read all data from istream
std::string line{};
while (getline(is, line)) {
// Search for 2 doubles
std::smatch sm;
if (std::regex_search(line, sm, reDouble)) {
// Convert found strings to double
double d1{std::stod(sm[1])};
// Do some calculations
d1 = d1 + 10.0;
// Push back into vector
dd.emplace_back(d1);
}
else
std::cerr << "Error found in line: " << line << "\n";
}
return is;
}
int main()
{
// Define vector and fill it
VectorDouble dd{};
(void)get(input, dd);
// Some debug output
for (double& d : dd) {
std::cout << d << "\n";
}
return 0;
}
为什么不用semantic actions来进行算术运算?
在下面的代码中:
#include <iostream>
#include <sstream>
#include <string>
#include <cstdio>
#include <vector>
using VectorDouble = std::vector<double>;
void show( VectorDouble const& dd)
{
std::cout<<"vector result=\n";
for (double const& d : dd) {
std::cout << d << "\n";
}
}
auto arith_ops=[](double&x){ x+=10.0;};
std::string input_err_yes{R"(0.0
1.5
2.0xxx
not double
4.0
-5.0
)"};
std::string input_err_not{R"(0.0
1.5
2.0
3.0
4.0
-5.0
)"};
void stod_error_recov(std::string const&input)
//Use this for graceful error recovery in case input has syntax errors.
{
std::cout<<__func__<<":\n";
VectorDouble dd;
std::istringstream is(input);
std::string line{};
while (getline(is, line) ) {
try {
std::size_t eod;
double d1(std::stod(line,&eod));
arith_ops(d1);
dd.emplace_back(d1);
auto const eol=line.size();
if(eod!=eol) {
std::cerr << "Warning: trailing chars after double in line: "<< line << "\n";
}
}
catch (const std::invalid_argument&) {
if(!is.eof())
std::cerr << "Error: found in line: " << line << "\n";
}
}
show(dd);
}
void stod_error_break(std::string const&input)
//Use this if input is sure to have correct syntax.
{
std::cout<<__func__<<":\n";
VectorDouble dd;
char const*d=input.data();
while(true) {
try {
std::size_t eod;
double d1(std::stod(d,&eod));
d+=eod;
arith_ops(d1);
dd.emplace_back(d1);
}
catch (const std::invalid_argument&) {
//Either syntax error
//Or end of input.
break;
}
}
show(dd);
}
#include <boost/spirit/home/x3.hpp>
void x3_error_break(std::string const&input)
//boost::spirit::x3 method.
{
std::cout<<__func__<<":\n";
VectorDouble dd;
auto f=input.begin();
auto l=input.end();
using namespace boost::spirit::x3;
auto arith_action=[](auto&ctx)
{ arith_ops(_attr(ctx));
};
phrase_parse(f, l, double_[arith_action] % eol, blank, dd);
show(dd);
}
int main()
{
//stod_error_recov(input_err_yes);
//stod_error_break(input_err_not);
x3_error_break(input_err_not);
return 0;
}
stod_* 函数与 Armin 的不同,不需要 regex
因为
std:stod 进行解析,因为它不
使用 regex
它可能运行得更快一些。
有 2 个带有源代码注释的 stod_* 函数 指出应该使用哪个。
为了完整起见,使用 boost::spirit::x3 的第三个函数是 显示。恕我直言,它的可读性比其他的要好;然而, 编译可能需要更多时间。