DEKKER
DEKKER

Reputation: 921

string stream never terminates in while loop

I want to write a generic function to parse CSV files. My code acts very strange as it never stops and repeats the first line forever. What am I doing wrong here?

#include <vector>
#include <string>
#include <sstream>
#include <iostream>
std::vector<std::vector<std::string>> parseCsvFile(std::string_view source,
                                                   char valueSeparator) {
    auto reult = std::vector<std::vector<std::string>>();
    for(std::string line;
        std::getline(std::istringstream(source.data()), line);
        /* emoty cond */) {
        std::istringstream stream(line);
        std::string token;

        while(std::getline(stream, token, valueSeparator)) { // never ends
            // debug
            std::cout << token << "\n" << std::endl;
            // push to vector
        }
    }

    return reult;
}

void test() {
    auto testData = std::string("a,b,c,d\r\ne,f,g,h\r\n");
    const auto data = parseCsvFile(testData, ','); // Never ends
}

Upvotes: 0

Views: 93

Answers (2)

Some programmer dude
Some programmer dude

Reputation: 409482

The problem is with the for loop:

for(std::string line;
    std::getline(std::istringstream(source.data()), line);
    /* emoty cond */)

The expression std::istringstream(source.data()) creates a brand new istringstream object from scratch each iteration of the loop. You never get beyond the first line in the input string source.

You need to create the string stream before the loop, and then use it in the loop:

std::istringstream source_stream(source.data());
for(std::string line;
    std::getline(source_stream, line);
    /* emoty cond */)

On a different note: The term "cond" means a "condition". And the condition isn't empty, it's the third "expression" clause that's empty. The condition is the std::getline call.

Upvotes: 4

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 123439

You create a new istringstream on every iteration, hence reading one line from it will never reach the end. You want to construct one stream only:

std::istringstream is(source.data());
for(std::string line; std::getline(is, line); ) {
       // ... 

Live Demo

Upvotes: 1

Related Questions