user1543042
user1543042

Reputation: 3442

C++ Parse line of doubles of variable length

I am trying to read in a file line by line, parse it based on spaces and place it into a vector called input. However, I cannot do a cin >> x1 >> x2 >> x3 ... because the line doesn't have a set number of terms. Below is what I was thinking, but it could be wrong.

vector <double> input;
fstream inputFile("../Sphere.in", fstream::in);
inputFile.open("../Sphere.in", fstream::in);

while (inputFile.good())
{
    getline(inputFile, line);

then something in here that says for each space in line put in input[i]

 }

I am very new at C++ and would appreciate any help that someone could throw my way.

Thanks,

John

Upvotes: 0

Views: 1889

Answers (2)

Kerrek SB
Kerrek SB

Reputation: 476930

If you just want one flat collection of doubles:

#include <vector>
#include <istream>     //  for operator>>
#include <fstream>     //  for std::ifstream

std::vector<double> v;
for (double d; inputFile >> d; ) { v.push_back(d); }

Or simpler:

// includes as above
#include <iterator>

std::vector<double> v((std::istream_iterator<double>(inputFile)),
                      std::istream_iterator<double>());

If you want a container for each line:

// includes as above
#include <string>
#include <sstream>

std::vector<std::vector<double>> v;

for (std::string line; std::getline(inputFile, line); )
{
    std::istringstream iss(line);
    v.emplace_back(std::istream_iterator<double>(iss),
                   std::istream_iterator<double>());
}

In the line-by-line approach, you could also check if you've successfully reached the end of the input string, or whether you were stopped by invalid input and emit a diagnostic. If you want to take error checking to an extreme, you could extract individual strings from the stream and parse them as double (using std::strtod) and emit a diagnostic if that fails, skipping the unparsable tokens:

// ...
#include <cstdlib>

for (std::string line; std::getline(inputFile, line); )
{
    std::istringstream iss(line);
    v.emplace_back();

    for (std::string token; iss >> token; )
    {
        char * e;
        double const d = std::strtod(token.c_str(), &e);
        if (*e != '\0') { /* error! skip this token */ continue; }
        v.back().emplace_back(d);
    }
}

Upvotes: 4

jrok
jrok

Reputation: 55395

while (inputFile.good()) is wrong, as it only evaluates to false after a read fails. Without additional checks inside the loop, the last iteration will work on invalid input. The correct, idiomatic way is to put the read in loop's condition:

while (getline(inputFile, line)) { ... }

This way you only enter the loop if getline succeeds. Now you can construct a string stream from line and read doubles from there, using similar approach with read inside loop condition:

while (getline(inputFile, line)) {
    istringstream iss(line);
    double d;
    while (iss >> d) input.push_back(d);
}

Upvotes: 2

Related Questions