boost::spirit::x3 phrase_parse 在进入 Vector 之前进行算术运算

boost::spirit::x3 phrase_parse doing arithmetic operations before pushing into vector

本文关键字:Vector 算术运算 x3 spirit phrase parse boost      更新时间:2023-10-16

我正在为我的大学研究做一个项目。我的目标是将大文件(2,6 GB(中的双精度数读取为双精度向量。

我正在使用带有 mmap 的提升精神 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 successn";
        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 双精度。

然后我们读取这个双精度,做一些计算,然后将其推入向量。

请参阅以下非常简单的代码。

#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;
}

为什么不使用语义操作来执行算术运算?

在下面的代码中:

#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;
}

与Armin不同,stod_*功能不需要regex因为std:stod 进行解析,因为它没有使用regex它可能会运行得更快一些。

有 2 个 stod_* 函数显示在源代码注释中指示应使用哪个。

为了完整起见,使用 boost::spirit::x3 的 3ird 函数是显示。 恕我直言,它的可读性比其他的更好;然而编译可能需要更多时间。