1

I've spent almost 4 hours trying to get past this issue...

I have a text file with over 100 rows. Each row has 4 values separated by commas. I want to be able to extract each value and save it into a variable (v1...v4).

I have used a for loop, as I won't be reading the entire contents of the file. I'm just trying to get 1 working for now.

So far, I have managed to read a single row. I just need to break the row up now. This is for my Uni assignment, and I am not allowed to use any boost or tokeniser classes. Just getline and other basic commands.

I have this code:

// Read contents from books.txt file
ifstream theFile("fileName.txt");
string v1, v2, v3, v4, line;

for (int i = 0; i < 1; i++) {
    getline(theFile, line, '\n');
    cout << line << endl;  // This part works fine
    getline(line, v1, ",");  // Error here
    cout << v1 << endl;
    getline(line, v2, ",");  // Error here
    cout << v2 << endl;
    getline(line, v3, ",");  // Error here
    cout << v3 << endl;
    getline(line, v4, '\n');  // Error here
    cout << v4 << endl;
}

theFile.close();

The error I get is - error: no matching function for call to ‘getline(std::string&, std::string&, const char [2])

How can I fix this?

CocaCola
  • 751
  • 3
  • 10
  • 21
  • possible duplicate of [How to read-write into/from text file with comma separated values](http://stackoverflow.com/questions/1474790/how-to-read-write-into-from-text-file-with-comma-separated-values) – Bo Persson Sep 02 '12 at 09:28
  • @BoPersson It's not really a duplicate, since this post is about a syntax error and the other is more about semantics – xQuare Sep 02 '12 at 09:41
  • @user - It is a duplicate of all the questions Sandra has been asking about reading a CSV file. And it shows how to do it. – Bo Persson Sep 02 '12 at 09:44
  • I thought that Sandras problem was the above mentioned function call, which is simply unknown to the linker since it is called in the wrong manner? – xQuare Sep 02 '12 at 09:47
  • You have commented the last call a also resulting in an error, but I am not convinced that is true. It would be better to also post the copy & pasted compiler log output verbatim rather than elide or paraphrase the output. – Clifford Sep 02 '12 at 11:00

4 Answers4

2

The delimiter for getline is a character. You have used double-quote marks "," which represent a string (hence why the compiler error indicates that you've used char[2] - string literals contain an additional 'nul' character).

Single character values are represented using single quotes instead:

getline(myFile, v1, ',');

edit - I've just noticed you're passing a string as the first parameter, which getline doesn't support (it won't let you retrieve tokens directly from a string). You probably wanted to stuff the string into a stringstream instead

#include <sstream>

// etc ...

std::string csv = "the,cat,sat,on,the,mat";
std::istringstream buffer( csv );
std::string token;

while( std::getline( buffer, token, ',' ) )
{
    std::cout << token << std::endl;
}
Ben Cottrell
  • 5,741
  • 1
  • 27
  • 34
  • The new error is no matching function for call to ‘getline(std::string&, std::string&, char) – CocaCola Sep 02 '12 at 09:16
  • @Sandra - indeed I see that now. credit to the other answer for spotting it too. Updated my answer with a slightly more complete example. – Ben Cottrell Sep 02 '12 at 09:19
  • I'm not sure if I can use the sstream library. Is there a way to do easily it using getline? – CocaCola Sep 02 '12 at 09:24
  • @Sandra You can read it directly from the file instead if you prefer. There's nothing stopping you from reading each token out of your file directly (i.e. `getline( theFile, v1, ',' )` ) instead of reading an entire line into a string then splitting it afterwards. `istringstream` and `ifstream` both derive from `istream` and therefore can be used interchangably with getline. – Ben Cottrell Sep 02 '12 at 09:28
  • Fantastic. I fixed it. I did this for (int i = 0; i < 2; i++) { getline(file, v1, ','); cout << v1 << endl; getline(file, v2, ','); cout << v2 << endl; getline(file, v3, ','); cout << v3 << endl; getline(file, v4, '\n'); cout << v4 << endl; } – CocaCola Sep 02 '12 at 10:46
2

According to this page, you have to call getline with std::istream as the first parameter.

But line is of type std::string. You should pass a std::istream instead, which can be done by creating an std::istringstream from line. This could work:

string v1, v2, v3, v4, line;
istringstream line_stream;

for (int i = 0; i < 1; i++) {
    getline(theFile, line, '\n');
    cout << line << endl;
    line_stream.str(line); // set the input stream to line
    getline(line_stream, v1, ","); // reads from line_stream and writes to v1
...

If you want to read more about std::istringstream, you can do that here.

Also, according to the above page, the third parameter has to be of type char. But you pass "," which will automatically converted to const char[2], a string. For characters, you use 'c'.

xQuare
  • 1,293
  • 1
  • 12
  • 21
  • Updated. You can set the input string with .str(). I recommend you to take a look at the page for istringstream in my post, since it will answer most of your questions about how to use that class. If something is still unclear, you should ask. – xQuare Sep 02 '12 at 10:39
  • Thanks for the response, but I had to try and do it with getline :) – CocaCola Sep 02 '12 at 10:48
  • I think this is with getline :o This is the same code as yours, it just works. – xQuare Sep 02 '12 at 11:46
0
string filename, text, line;
vector<string> v1; 
vector<string> v2;
vector<string> v3;
vector<string> v4;
int i = 0, k = 0, n;
cout << "Enter filename." << endl;
cin >> filename;
cout << "How many lines of text are in the file?" << endl;
cin >> n;
cin.ignore(200, '\n');
ifstream file(filename.c_str());
if (!file) {
           cerr << "No such file exists." << endl;
           exit(1);
           }
cin.ignore(200, '\n');
if (file.is_open()) {
    while (file.good()) {
           for (k = 0; k < n; k++) { //Loops for as many lines as there are in the file
                for (i = 0; i < 4; i++) { //Loops for each comma-separated word in the line
                              getline(cin, text, ',');
                              if (i == 0)
                                    v1.push_back(text);
                              else if (i == 1)
                                   v2.push_back(text);
                              else if (i == 2)
                                   v3.push_back(text);
                              else if (i == 3)
                                   v4.push_back(text);
                               }
                              }
                          }
                }
file.close();
return 0;
}
Spudley
  • 166,037
  • 39
  • 233
  • 307
user1641700
  • 53
  • 3
  • 9
0

There are two overloads for std::getline:

istream& getline ( istream& is, string& str, char delim );
istream& getline ( istream& is, string& str );

Three of your calls pass a literal string constant as the third parameter, where a single char is required. Use ' rather than " for character constants.

Clifford
  • 88,407
  • 13
  • 85
  • 165