Dinosaur
Dinosaur

Reputation: 675

Reading two columns in CSV file in c++

I have a CSV file in the form of two columns: name, age

To read and store the info, 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 the whole line instead of just the name. How could I possibly avoid this problem so that I can read the integer into age?

Thank you!

Upvotes: 5

Views: 10937

Answers (3)

vsoftco
vsoftco

Reputation: 56547

You can first read the whole line with std:getline, then parse it via a std::istringstream (must #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 fully working general example that tokenizes a 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;
    }
}

Upvotes: 6

Leo Lindhorst
Leo Lindhorst

Reputation: 232

You maybe could use stringstreams for that, but I wouldn't trust this, if I'm honest. If I was you, I would write a small function, that reads the whole line into a string and after that, it should search for the separator character in the string. Everything in front of that is the first column and everything behind the second one. With the string operations provided by C++ you can move these parts in your variables (you can convert them into the correct type if you need). I wrote a small C++ Library for CSV parsing, maybe a look at it helps you. You can find it on GitHub.

EDIT: In this Gist you can find the parsing function

Upvotes: 0

R Sahu
R Sahu

Reputation: 206567

read>>name gave me the whole line instead of just the name. How could I possibly avoid this problem so that I can read the integer into age?

read >> name will read everything into name until a white space is encountered.

If you have a comma separated line without white spaces, it makes sense that the entire line is read into name.

You can use std::getline to read the entire line to one string. Then use various methods of tokenizing a std::string.

Sample SO posts that address tokenizing a std::string:

How do I tokenize a string in C++?
c++ tokenize std string
Splitting a C++ std::string using tokens, e.g. ";"

Upvotes: 0

Related Questions