Reading two columns in a CSV file in C ++
I have a CSV file as two columns: name, age
To read and save the information, I did this
struct person
{
string name;
int age;
}
person record[10];
ifstream read("....file.csv");
However, when I did
read >> record[0].name;
read.get();
read >> record[0].age;
read -> name gave me a whole string instead of a name. How could I avoid this problem so that I can read the integer age?
Thank!
You can read the whole line from first std:getline
, then parse it with std::istringstream
(required #include <sstream>
) like
std::string line;
while (std::getline(read, line)) // read whole line into line
{
std::istringstream iss(line); // string stream
std::getline(iss, record[0].name, ','); // read first part up to comma, ignore the comma
iss >> record[0].age; // read the second part
}
Below is a complete working example that symbolizes the CSV file Live on Ideone
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
// in your case you'll have a file
// std::ifstream ifile("input.txt");
std::stringstream ifile("User1, 21, 70\nUser2, 25,68");
std::string line; // we read the full line here
while (std::getline(ifile, line)) // read the current line
{
std::istringstream iss{line}; // construct a string stream from line
// read the tokens from current line separated by comma
std::vector<std::string> tokens; // here we store the tokens
std::string token; // current token
while (std::getline(iss, token, ','))
{
tokens.push_back(token); // add the token to the vector
}
// we can now process the tokens
// first display them
std::cout << "Tokenized line: ";
for (const auto& elem : tokens)
std::cout << "[" << elem << "]";
std::cout << std::endl;
// map the tokens into our variables, this applies to your scenario
std::string name = tokens[0]; // first is a string, no need for further processing
int age = std::stoi(tokens[1]); // second is an int, convert it
int height = std::stoi(tokens[2]); // same for third
std::cout << "Processed tokens: " << std::endl;
std::cout << "\t Name: " << name << std::endl;
std::cout << "\t Age: " << age << std::endl;
std::cout << "\t Height: " << height << std::endl;
}
}
read>>name
gave me a whole string instead of a name. How could I avoid this problem so that I can read the integer age?
read >> name
will read everything in name
until empty space is encountered.
If you have a comma-delimited string with no spaces, it makes sense that the entire string is read into name
.
You can use std::getline
to read the entire line down to one line. Then use various methods of tokenizing a std::string
.
An example of SO posts that address tokenization std::string
:
How to tokenize a string in C ++?
C ++ tokenize std string
Splitting a C ++ std :: string using tokens, e.g. ""
Perhaps you could use stringstream for this, but I wouldn't trust it to be honest. If I were you, I would write a little function that reads the entire string into a string, and after that it should look for the delimiter character in the string. This is preceded by the first column and everything behind the second. With the string operations provided by C ++, you can move these parts around in your variables (you can convert them to the correct type if you need to). I wrote a small C ++ library for CSV parsing, maybe this will help you. You can find it on GitHub .
EDIT: In this Gist you can find the function