0

I am new in C++, actually learning to do the assignments from the Masters I am studying.

Firstly in my code, I need to read each row and column from a csv file and store it in an array[][].

My CSV file is(columns A1, A2, B1, B2):

46842 test
46825 test2

My code atm is:

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main(){
    string val;
    string arr[2][2];

    ifstream myFile;
    myFile.open("excel.csv");
    while (myFile.good())
    {    
        for(int row = 0; row <= 1; row++)
        {
            for(int column = 0; column <= 1; column++)
            { 
                getline(myFile, val, ',');
                arr[row][column] = val;
            }
        }         
    }
    cout <<"cell 0.0: " << arr[0][0] << endl;
    cout <<"cell 0.1: " << arr[0][1] << endl;
    cout <<"cell 1.0: " << arr[1][0] << endl;
    cout <<"cell 1.1: " << arr[1][1] << endl;

}

The problem is the outcome:

cell 0.0: 46842
cell 0.1: test
46825
cell 1.0: test2

cell 1.1: test2

It should be:

cell 0.0: 46842
cell 0.1: test
cell 1.0: 46825
cell 1.1: test2

it seems like the problem is when it reaches the last position of the first row. Does anyone know how to fix this? Thanks :)

A M
  • 14,694
  • 5
  • 19
  • 44
  • 2
    `getline(myFile, val, ',');` is only going to stop for commas. The newlines don't matter to it anymore. You can adapt the trick used in [Option 2 of this answer](https://stackoverflow.com/a/7868998/4581301) to do what you want. – user4581301 May 07 '20 at 03:03
  • I changed my code to NOT use the delimiter comma inside the getline(). So now basically reads the whole line separating by comma like 46842,test and 46825,test2. Now just need to find a way to break this by the comma and store in an array[][]. I am having a look in the link you posted, thanks. Any specific function to read this, knowing I will need to read it inside an array like array[row][column] ?? thank you – Fernando Salviati May 07 '20 at 03:38
  • 1
    You can make two nested loops. The outer loop will read complete lines (delimited by `'\n'`). Then you can use `std::istringstream` with the `std::string` (with current line) to parse the cells of this line (delimited by `','`) in the inner loop. – Scheff's Cat May 07 '20 at 05:10
  • I tried using the solution proposed above, it works better but not yet ideally. This is part of my code, now it prints: cell 0.0: 46842 cell 0.1: test cell 1.0: 46842 cell 1.1: test – Fernando Salviati May 07 '20 at 06:14

2 Answers2

1

You made some mistakes that need to be fixed. You used std::getline to read until the next comma. It will do exactly that, even if a new line starts. So it will continue tor read until it finds the next comma. This will explain the output of

cell 0.1: test
46825

It shows "test", then the new line and then 46825.

So, this will not work. We need to use a line based approach. We will first read a complete line 46842,test and then split it. We will use std::getline to split it. But now, it will work, becuase it will extract data until the next comma or until the end of the line.

You should also never use:

while (myFile.good())

Please see 3 possible solutions:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

int main() {
    string val;
    string arr[2][2];

    ifstream myFile;
    myFile.open("excel.csv");
    int row = 0;
    while (getline(myFile,val))
    {
        std::istringstream iss(val);
        for (int column = 0; column <= 1; column++)
        {
            getline(iss, arr[row][column], ',');
        }
        ++row;
    }
    cout << "cell 0.0: " << arr[0][0] << endl;
    cout << "cell 0.1: " << arr[0][1] << endl;
    cout << "cell 1.0: " << arr[1][0] << endl;
    cout << "cell 1.1: " << arr[1][1] << endl;

}

Next improvement

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>


int main() {

    std::string val;
    std::string arr[2][2];

    std::ifstream myFile;
    myFile.open("excel.csv");

    for (unsigned int row = 0; std::getline(myFile, val); ++row)
    {
        std::istringstream iss(val);
        for (unsigned int column = 0; column <= 1; column++)
        {
            std::getline(iss, arr[row][column], ',');
        }
    }

    std::cout << "cell 0.0: " << arr[0][0] << std::endl;
    std::cout << "cell 0.1: " << arr[0][1] << std::endl;
    std::cout << "cell 1.0: " << arr[1][0] << std::endl;
    std::cout << "cell 1.1: " << arr[1][1] << std::endl;

}

Full C++ solution:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>

int main() {

    // Here we will store all data from our CSV file
    std::vector<std::vector<std::string>> data{};

    // Open the csv file with the source data
    std::ifstream myFile{ "excel.csv" };

    // Check, if we could open the source file
    if (myFile) {

        // We will read all lines of the source file in a for loop
        for (std::string line{}; std::getline(myFile, line); ) {

            // Stuff the line in an std::istringstream, so that we can extract data of jkust one line
            std::istringstream lineAsStream{ line };

            // The single parts of one line
            std::vector<std::string> parts{};

            for (std::string partData{}; std::getline(lineAsStream, partData, ','); parts.push_back(partData))
                ; // Empty body

            // Store new row data
            data.push_back(parts);
        }
        std::cout << "cell 0.0: " << data[0][0] << std::endl;
        std::cout << "cell 0.1: " << data[0][1] << std::endl;
        std::cout << "cell 1.0: " << data[1][0] << std::endl;
        std::cout << "cell 1.1: " << data[1][1] << std::endl;
    }
    else {
        std::cerr << "\n***Error: COuld not open source file\n";
    }
    return 0;
}
A M
  • 14,694
  • 5
  • 19
  • 44
  • Thanks Armin! Thank you so much, that's just amazing, all the solutions proposed work well. I will study these codes to understand how you did it. Thanks again :) – Fernando Salviati May 07 '20 at 07:16
  • @FernandoSalviati This is indeed a nice answer. To be fair, you can pay by checking it as accepted. ([What should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers)) You may also leave an upvote which will not yet count but maybe later if you earned some rep. yourself. "Thank you"-comments are actually against the recommendation (but I never saw a complaint than the answer was accepted also). An answerer which got acception may pay back to the questioner with an upvote as well. (Makes sense if the question was worth to answer.) – Scheff's Cat May 07 '20 at 12:37
0

This is my code atm. it prints:

    cell 0.0: 46842 
    cell 0.1: test 
    cell 1.0: 46842 
    cell 1.1: test 

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>

using namespace std;

main() {
   string arr[2][2];
   string val;
   string my_str; 
   ifstream myFile;
   myFile.open("excel.csv");   

   for(int row = 0; row <= 1; row++) {
       getline(myFile, val);
       stringstream s_stream(val);
       for(int column = 0; column <= 1; column++) {                            
           string substr;
           getline(s_stream, substr, ',');
           result.push_back(substr);
           arr[row][column] = result.at(column);
       }
   }
   cout <<"cell 0.0: " << arr[0][0] << endl;
   cout <<"cell 0.1: " << arr[0][1] << endl;
   cout <<"cell 1.0: " << arr[1][0] << endl;
   cout <<"cell 1.1: " << arr[1][1] << endl;
}
A M
  • 14,694
  • 5
  • 19
  • 44