26

I have this code which is supposed to cout in console the information from the .csv file;

while(file.good())
{

    getline(file, ID, ',');
    cout << "ID: " << ID << " " ; 

    getline(file, nome, ',') ;
    cout << "User: " << nome << " " ;

    getline(file, idade, ',') ;
    cout << "Idade: " << idade << " "  ; 

    getline(file, genero, ' ') ; 
    cout << "Sexo: " <<  genero<< " "  ;

}

And a csv file that has this (when I open with notepad):

0,Filipe,19,M

1,Maria,20,F

2,Walter,60,M

Whenever I run the program the console will display this:

Unexpected output

My question is why isn't the program repeating those cout messages in every line instead of only in the first one

Btw , nome is name, idade is age, and genero/sexo is gender, forgot to translate before creating this post

Mr. Phil
  • 1,099
  • 2
  • 14
  • 31
  • 1
    I was looking for an easy way to do this, if possible. The link you posted is like chinese for me regarding my current knowledge – Mr. Phil May 08 '13 at 17:31
  • 5
    @FreemanZhang: That's C#, this is C++. – Eddy Luten May 08 '13 at 17:32
  • @FilipeGama: You have two issues, (A) the delimiter mentioned in the answers, and (B), you're checking if the input was valid in the wrong place. If you only fix A, this will cause the last line to appear duplicated. – Mooing Duck May 08 '13 at 21:35
  • @Mooing Duck Yes it will, but just sometimes and can't figure out why, could you explain me where should I check if the input was valid? – Mr. Phil May 08 '13 at 22:55
  • @FilipeGama: If you do an input operation, test if it succeeded. Streams propogate the failure though, so you only have to test if the last one succeeded, which is awesome. – Mooing Duck May 08 '13 at 22:57

4 Answers4

28

You can follow this answer to see many different ways to process CSV in C++.

In your case, the last call to getline is actually putting the last field of the first line and then all of the remaining lines into the variable genero. This is because there is no space delimiter found up until the end of file. Try changing the space character into a newline instead:

    getline(file, genero, file.widen('\n'));

or more succinctly:

    getline(file, genero);

In addition, your check for file.good() is premature. The last newline in the file is still in the input stream until it gets discarded by the next getline() call for ID. It is at this point that the end of file is detected, so the check should be based on that. You can fix this by changing your while test to be based on the getline() call for ID itself (assuming each line is well formed).

while (getline(file, ID, ',')) {
    cout << "ID: " << ID << " " ; 

    getline(file, nome, ',') ;
    cout << "User: " << nome << " " ;

    getline(file, idade, ',') ;
    cout << "Idade: " << idade << " "  ; 

    getline(file, genero);
    cout << "Sexo: " <<  genero<< " "  ;
}

For better error checking, you should check the result of each call to getline().

Community
  • 1
  • 1
jxh
  • 69,070
  • 8
  • 110
  • 193
  • @FilipeGama: Did you try my suggested fix? – jxh May 08 '13 at 18:32
  • Yes, the second one worked :) Thanks, as i said in other answer I would upvote but can't because don't have enough points – Mr. Phil May 08 '13 at 20:44
  • @user315052: There's two issues: (A) the delimiter mentioned in the answers, and (B), you're checking if the input was valid in the wrong place. If you only fix A, this will cause the last line to appear duplicated. – Mooing Duck May 08 '13 at 21:36
  • @user315052 Thanks, I've just accepted your answer for being the most complete, thanks to MooingDuck too. Gratz, still no way to upvote – Mr. Phil May 08 '13 at 22:58
13

a csv-file is just like any other file a stream of characters. the getline reads from the file up to a delimiter however in your case the delimiter for the last item is not ' ' as you assume

getline(file, genero, ' ') ; 

it is newline \n

so change that line to

getline(file, genero); // \n is default delimiter
AndersK
  • 35,813
  • 6
  • 60
  • 86
  • 1
    Just what I wanted to write, so +1. This code doesn't look for the newline character, which leads for the rest not being parsed correctly. – Refugnic Eternium May 08 '13 at 18:16
  • thanks that solved the problem , finally :) I'd vote you up but don't have enough points so here is my comment, gratz – Mr. Phil May 08 '13 at 18:26
  • @FilipeGama An 'upvote' isn't the only way to say 'Thank you'. Accepting their answer is another perfectly valid way to appreciate their effort. – Refugnic Eternium May 08 '13 at 18:29
  • np Filipe, just happy to help – AndersK May 08 '13 at 20:17
  • @Refugnic Eternium @ claptrap Didn't know about that, already "accepted" – Mr. Phil May 08 '13 at 20:55
  • @claptrap: There's two issues: (A) the delimiter mentioned in the answers, and (B), you're checking if the input was valid in the wrong place. If you only fix A, this will cause the last line to appear duplicated. – Mooing Duck May 08 '13 at 21:35
  • @Mooing Duck is right, I just realised that later...it's duplicating the last line, how should I do it then? Thanks in advance :) – Mr. Phil May 08 '13 at 22:56
4

Your csv is malformed. The output is not three loopings but just one output. To ensure that this is a single loop, add a counter and increment it with every loop. It should only count to one.

This is what your code sees

0,Filipe,19,M\n1,Maria,20,F\n2,Walter,60,M

Try this

0,Filipe,19,M
1,Maria,20,F
2,Walter,60,M


while(file.good())
{

    getline(file, ID, ',');
    cout << "ID: " << ID << " " ; 

    getline(file, nome, ',') ;
    cout << "User: " << nome << " " ;

    getline(file, idade, ',') ;
    cout << "Idade: " << idade << " "  ; 

    getline(file, genero) ; \\ diff
    cout << "Sexo: " <<  genero;\\diff


}
Ian Jenkins
  • 109
  • 2
  • 8
  • If it's not 3 loops how does it display 2nd and 3rd line (even without the couts? Sorry I'm struggling to understand these .csv concepts , thanks in advance edit: if you could edit my code and post it here I'd be very thankful :) – Mr. Phil May 08 '13 at 17:40
  • It kinda worked but now I got this : https://dl.dropboxusercontent.com/u/4613740/console2.png It repeats the last line for some reason... – Mr. Phil May 08 '13 at 17:44
  • Again that will only work well for the 1st line, the others it'll just mess up... this way : https://dl.dropboxusercontent.com/u/4613740/console3.png – Mr. Phil May 08 '13 at 18:10
  • Hadn't noticed the commas, still : https://dl.dropboxusercontent.com/u/4613740/console4.png Repeats the last line and inserts new lines before ID :( it's driving me nuts... – Mr. Phil May 08 '13 at 18:20
  • I have corrected the code and the csv, (I didn't have a compiler before). The repeated lines are due to a blank line at the end of your .csv – Ian Jenkins May 08 '13 at 21:02
  • @IanJenkins: Correct code would make that less of an issue: http://coliru.stacked-crooked.com/view?id=13ce5945dc6733d4745c9e1e50813ce5-50d9cfc8a1d350e7409e81e87c2653ba – Mooing Duck May 08 '13 at 21:41
-6

That because your csv file is in invalid format, maybe the line break in your text file is not the \n or \r

and, using c/c++ to parse text is not a good idea. try awk:

 $awk -F"," '{print "ID="$1"\tName="$2"\tAge="$3"\tGender="$4}' 1.csv
 ID=0   Name=Filipe Age=19  Gender=M
 ID=1   Name=Maria  Age=20  Gender=F
 ID=2   Name=Walter Age=60  Gender=M
Freeman Zhang
  • 163
  • 1
  • 3
  • 12