0

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
}
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
DEKKER
  • 877
  • 6
  • 19
  • 2
    please do not remove includes from the code. It does not make the code simpler or easier to read. Anybody who wants to compile your code to reproduce the issue has to add them back – 463035818_is_not_an_ai Apr 24 '23 at 09:14
  • 1
    You construct a new `istringstream` every time around the loop, with the expression `std::istringstream(source.data())`. If you are not modifying `source` in the loop, and it's non-empty, the loop will never terminate. – paddy Apr 24 '23 at 09:14
  • 1
    The loop that never ends is the outer `for` loop. You just read the same data over and over. – john Apr 24 '23 at 09:14
  • 1
    Perhaps you meant something like `std::istringstream buffer(source.data()); for(std::string line; std::getline(buffer, line); /* emoty cond */)` – john Apr 24 '23 at 09:16
  • Parsing real csv files is more complicated than just separating on commas. – n. m. could be an AI Apr 24 '23 at 09:32
  • @n.m. well can you please mention a couple of points that one should take care of? – DEKKER Apr 24 '23 at 09:36
  • 1
    https://www.rfc-editor.org/rfc/rfc4180#page-2 – n. m. could be an AI Apr 24 '23 at 09:57

2 Answers2

4

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.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

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

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185