Search code examples
c++stringcsvparsingvector

read csv string into vector C++


There are many options of csv to vector, including read a csv file and and add its all data into vector in c++ however I want to something a bit above or below csv -> vector. Instead, I have a CURL function that loads csv data into a std::string in the format of

col1,col2,col3
abc,2,ghi
jkl,2,pqr

which, each row is separated by \n. How can I parse data in this given structure into a std::vector<data>

Where data would look something like

struct data
{
  std::string col1, col3;
  int col2;
};

Solution

  • If it is only parser you need to crate in your application, you can build some simple streaming recursive parser like this:

    #include <cctype>
    #include <cstring>
    #include <vector>
    #include <string>
    #include <iostream>
    
    struct data
    {
      std::string col1;
      int col2;
      std::string col3;
    };
    
    std::ostream& operator<<(std::ostream& to,const data& d)
    {
        to << d.col1 << ',';
        to << d.col2 << ',';
        to << d.col3;
        return to;
    }
    
    static char* skip_spaces(const char* csv)
    {
      constexpr const char* WHITESPACE = "\t\n\v\f\r ";
      return const_cast<char*>( csv + std::strspn(csv,WHITESPACE) );
    }
    
    
    static const char* parse_csv_line(const char* csv, data& to)
    {
      char* b = skip_spaces(csv);
      char* e = std::strchr(b,',');
      to.col1 = std::string(b,e);
      b = skip_spaces(e+1);
      e = std::strchr(b,',');
      to.col2 = std::strtol(b,&e,10);
      b = skip_spaces(e+1);
      e = std::strchr(b,'\n');
      if(nullptr == e) {
        e = b + std::strlen(b);
      }
      to.col3 = std::string(b,e);
      return ('\0' == *e) ? nullptr : e + 1;
    }
    
    std::vector<data> parse_csv(const char* csv)
    {
      std::vector<data> ret;
      // skip header
      csv = std::strchr(csv,'\n');
      while(nullptr !=  csv) {
        data next;
        csv = parse_csv_line(csv, next);
        ret.push_back( next );
      }
      return ret;
    }
    
    
    int main(int argc, const char** argv)
    {
      const char* CSV = "col1,col2,col3,\r\nabc,2,ghi\r\njkl,2,pqr";
      std::vector<data> parsed = parse_csv(CSV);
      for(auto d: parsed) {
        std::cout << d << std::endl;
      }
      return 0;
    }
    

    If you need something much more complex, i.e. handling errors etc use some CSV parsing library