3

Sorry if it's just pure stupidity but I'm stuck at a file reading problem via C++. This is the CSV data that I'd like to read:

5;1;0;3;3;5;5;3;3;3;3;2;3;3;0
5;1;0;3;3;5;0;3;3;3;3;2;0;0;3
5;1;1;3;3;0;0;0;0;3;5;2;3;3;3
0;3;5;5;0;2;0;3;3;0;5;1;1;0;0
0;0;3;5;5;2;0;0;0;0;5;5;1;1;0
0;0;0;0;5;2;0;0;0;0;0;5;5;1;0
;;;;;;;;;;;;;;
Code;Bezeichnung;Kosten;;;;;;;;;;;;
0;Ebene;6;;;;;;;;;;;;
1;Fluss;10; (begrenzt nutzbar);;;;;;;;;;;
2;Weg;2;;;;;;;;;;;;
3;Wald;8;;;;;;;;;;;;
4;Brücke;5;;;;;;;;;;;;
5;Felswand;12;;;;;;;;;;;;

here, I'd like to read the first values (separated by ;;;;) and store it in a 2 dimensional array. Which would not be a problem if it was seperated completely by ';'. But if use

while (getline(csvread, s, ';'))
{
[...]
}

I get information like this: {5}{1}{0}{3}{3}{5}{5}{3}{3}{3}{3}{2}{3}{3}{0\n5}{1} so it basically saves the newline and does not think of it as delimitator.

So is there an option to use getline even if you have two delimitators? Or am I completely off? I also thought about reading it line by line to a string, adding a ; to the string and rewriting it in a file in order to reuse getline using ;. But this can't seriously be the best option, right?

Marco A.
  • 43,032
  • 26
  • 132
  • 246
Rebecca
  • 459
  • 7
  • 21

4 Answers4

3

You should do the '\n' and ';' splitting separately:

// here split into lines by '\n'
while (getline(csvread, line, '\n'))
{
    // in here, split line by ;
    std::vector<std::string> elems;
    boost::split(elems, line, boost::is_any_of(";"));

    // do something with elems
}
malewick
  • 148
  • 5
Barry
  • 286,269
  • 29
  • 621
  • 977
2

you can use a splitting function like :

std::vector<std::string> split(const std::string& source, const std::string& delimiter){
    std::vector<std::string> result;

    size_t last = 0;
    size_t next = 0;

    while ((next = source.find(delimiter, last)) != std::string::npos){ 
        result.push_back(source.substr(last, next - last));
        last = next + delimiter.length();
    } 
    result.push_back(source.substr(last));
    return result;
}

now simply:

std::vector<std::vector<std::string>> parsedCSV;
while (getline(csvread, s, '\n'))
{
parsedCSV.push_back(split(s,";"));
}
David Haim
  • 25,446
  • 3
  • 44
  • 78
2

I recently had to read csv-data as well and stumbled upon the same 'problem'. Here's what I did:

  1. Read in a full line with getline(csvread, s), this will read up to the first newline.
  2. Split the string on every occurence of ;, I've used this StackOverflow answer as inspiration to split a string, the code is also listed below.

I didn't care much for performance as I only had to run this program once, I won't comment on the speed of this workaround.

Good luck!

Edit: apparently Boost offers code to split a string, that might be cleaner, consider the code below if you want to avoid Boost.


#include <string>
#include <sstream>
#include <vector>

// source: https://stackoverflow.com/a/236803/4841248

std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}


std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    split(s, delim, elems);
    return elems;
}
Community
  • 1
  • 1
Maarten Bamelis
  • 2,243
  • 19
  • 32
2

try something like this:

std::vector<std::string> cells;
while (getline(csvread, s) ){
   boost::split(cells, s, boost::is_any_of(";"));
   ....
}
Tim3880
  • 2,563
  • 1
  • 11
  • 14