繁体   English   中英

从C ++文件中读取不同类型的数字数据

[英]Reading numeric data of different types from a file in C++

我有一个文件,其前几行如下所示:

1   436.514    0.587    8.318   1  3        8 0.929        7 0.972        2 1.440
2   436.004    0.744    7.020   1  3       10 1.117        9 1.155        1 1.440
3   436.263    0.603    5.029   2  1        9 0.916
4   437.966    0.594    6.086   2  1        9 0.835
5   434.577    1.454    5.820   2  1       10 0.898
6   433.990    1.139    7.596   2  1       10 0.919
7   437.917    0.102    8.485   4  3        1 0.972       11 1.503       12 1.428
8   435.617    0.849    9.510   4  3       13 1.463        1 0.929       14 1.490
9   436.839    0.691    5.880   4  3        4 0.835        3 0.916        2 1.155
10   434.623    1.036    6.798   4  3        6 0.919        5 0.898        2 1.117
11   438.321   39.569    9.683   3  1        7 1.503
12   438.614   39.463    7.420   3  1        7 1.428
13   434.384    1.154    9.304   3  1        8 1.463

问题是我无法转换这些值,这些值在称为line的变量中作为字符串读取,然后存储到由空格分隔的单独char数组中。 但是我的问题是我无法使用std C ++函数将这些值转换为适当的类型。

我的意思是我不控制文件中各个位置的值,因此无法提供预定义的函数将其转换为该类型。

例如:在第一行中,第一个值是int,然后是3个浮点数,然后是int,依此类推。 而且每一行中值的数量也不是恒定的。 因此,我无法将它们转换为所需的类型。 我尝试了lexical_cast ,如果它们与预定义的类型不同,则无法转换值。

例如:如果我有话说

str = "123";
float num = lexical_cast<float>(str)

它给了我一个错误。 stofstod函数也是如此,它们只能转换具有该类型的值的字符串。

这是我现在的代码:

while (i < line.length()){
            if (line[i] != ' '){
                    a[j++] = line[i++];
                    if (i == line.length()){
                            a[j] = '\0';
                    ------->int num = std::stoi(a);
                            std::cout << num << "  ";
                    }
            }
            else{
                    a[j] = '\0'; j = 0;
        ----------->float num = std::stof(a);
                    std::cout << num << "  ";
                    while (line[i] == ' ') i++;
            }
    }

用箭头标记的地方是问题区域。 我能以任何方式轻松地将这些值读入适当类型的适当变量中吗?

注意:由于行数为100000,因此我无法手动插入每个变量并考虑其类型,因此无法实现。

我只有几分钟的时间,但是这里是合适的代码的概要,它假定您要同时将所有数据保留在内存中以进行某些跨线分析:

struct Data
{
    int a;
    float b, c, d;
    int e, f;
    std::vector<std::pair<int, float>> g;
};


int main()
{
    int line_num = 0;
    std::vector<Data> all_data;
    if (std::ifstream in(filename))
    {
        std::string line;
        while (getline(in, line))
        {
            ++line_num;
            std::istringstream iss(line);
            Data data;
            if (iss >> data.a >> data.b >> data.c >> data.d
                    >> data.e >> data.f)
            {
                int i; float f;
                while (iss >> i >> f)
                    data.g.push_back(std::make_pair(i, f));
                all_data.push_back(data);
            }
            else
                std::cerr << "unable to parse mandatory fields "
                    "from line #" << line_num << " '" << line
                    << "', ignoring and continuing...\n"; 
        }

        ... use all_data for whatever analysis you want...
    }
    else
        std::cerr << "unable to open file\n";
}

笔记

  • 逐行读取,然后使用istringstream解析出值
  • 使用额外的循环来读取多对int / float值,它们出现在行尾

我希望现在对您来说这太过分了。

仍要向公众展示如果您使用知道如何向AST数据类型投影的解析器生成器,优雅的代码将变得多么优雅。 这是一个Spirit示例,该示例自动处理对vector<line_rec>所有转换,其中line_rec为:

struct line_record {
    int   a;
    float b, c, d;
    int   e;
    // column f is rest.size()
    std::vector<std::pair<int, float> > rest;
};    

生活在Coliru

#include <boost/fusion/include/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

struct line_record {
    int   a;
    float b, c, d;
    int   e;
    // column f is rest.size()
    std::vector<std::pair<int, float> > rest;
};    

BOOST_FUSION_ADAPT_STRUCT(line_record, a, b, c, d, e/*, f*/, rest)


// define a Spirit Grammar
using Iterator = boost::spirit::istream_iterator;

namespace parser {
    static auto const line = [] {
        using namespace boost::spirit::qi;

        _a_type number_of_pairs;
        rule<Iterator, line_record(), locals<unsigned> > line_parser;

        return line_parser %= skip(blank) [
                    int_ >> float_ >> float_ >> float_ >> 
                    int_ >> omit[ uint_ [ number_of_pairs = _1 ] ] >> 
                    repeat(number_of_pairs) [ int_ >> float_ ] >>
                    (eol|eoi)
                ];
    }();
}

#include <fstream>

int main() {
    using namespace std;

    ifstream ifs("input.txt");
    Iterator first(ifs >> noskipws), last;

    vector<line_record> all_data;

    if (parse(first, last, *parser::line, all_data))
    {
        cout << "Parsed " << all_data.size() << " lines\n";
        for (auto& rec : all_data) {
            cout << rec.a << "\t"
                 << rec.b << "\t" << rec.c << "\t" << rec.d << "\t"
                 << rec.e << "\t"
                 << rec.rest.size();

            for (auto& trailing : rec.rest)
                cout << "\t(" << trailing.first << ", " << trailing.second << ")";

            cout << "\n";
        }
    } else {
        cout << "Parse failed\n";
    }

    if (first != last) {
        cout << "Remaining input: '" << string(first, last) << "'\n";
    }
}

输出量

根据您问题的输入:

Parsed 13 lines
1   436.514 0.587   8.318   1   3   (8, 0.929)  (7, 0.972)  (2, 1.44)
2   436.004 0.744   7.02    1   3   (10, 1.117) (9, 1.155)  (1, 1.44)
3   436.263 0.603   5.029   2   1   (9, 0.916)
4   437.966 0.594   6.086   2   1   (9, 0.835)
5   434.577 1.454   5.82    2   1   (10, 0.898)
6   433.99  1.139   7.596   2   1   (10, 0.919)
7   437.917 0.102   8.485   4   3   (1, 0.972)  (11, 1.503) (12, 1.428)
8   435.617 0.849   9.51    4   3   (13, 1.463) (1, 0.929)  (14, 1.49)
9   436.839 0.691   5.88    4   3   (4, 0.835)  (3, 0.916)  (2, 1.155)
10  434.623 1.036   6.798   4   3   (6, 0.919)  (5, 0.898)  (2, 1.117)
11  438.321 39.569  9.683   3   1   (7, 1.503)
12  438.614 39.463  7.42    3   1   (7, 1.428)
13  434.384 1.154   9.304   3   1   (8, 1.463)

您可以尝试使用ifstream.getline()和sscanf的组合来处理文件,该组合可以告诉它在一个字符串中找到了多少个匹配项。

#include <iostream>
#include <fstream>

#include <cstdio>

int main(void)
{
    double a, b, c, d, e, f;
    int i, j, k, l, m, n;
    char buffer[160];

    std::ifstream file;
    file.open("data.txt");
    while (!file.eof()) {
        // check if this fails
        file.getline(buffer, 160);

        if (file.eof()) break;

        a = b = c = d = e = f = 0.0;
        i = j = k = l = m = n = 0;

        int res = sscanf(buffer,
                         "%d %lf %lf %lf %d %d %d %lf %d %lf %d %lf",
                         &i, &a, &b, &c, &j, &k, &l, &d, &m, &e, &n, &f);
        std::cout << "Got " << res << " fields" << std::endl;
    }
}`

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM