I cannot believe that we are using a library for such an ultra simple thing like splitting a std::string
into tokens.
C++ has, since long, a build in and dedicated functionality, specifically designed for this purpose, to tokenize strings (split strings into tokens). And because such a simple dedicated function, designed for this purpose, is available, it simply should be used. There is no need for external libraries or complicated constructs. Simply use the std::sregex_token_iterator
.
This is an iterator (like many other iterators), that iterates over tokens (sub-strings) of a string. So, what we want.
We can then use the std::vector
s range constructor to write something simple like this:
std::vector tokens(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {}));
So, we define a variable with the name "tokens" of type std::vector
(with CTAD the type of the vector is automatically deduced). We use its range constructor and provide a begin and an end iterator. The begin iterator is the std::sregex_token_iterator
and the end-iterator is its default-initialized counterpart.
To put such a vector into a 2D Vector, we use the outer vectors emplace_back
function and do an inplace construction for the inner vector.
So you read the whole CSV-File with 2 statements
- a simple for loop
- a simple emplace back with the
std::sregex_token_iterator
// We will read all lines of the source file with a simple for loop and std::getline
for (std::string line{}; std::getline(csvFile, line); ) {
// We will split the one big string into tokens (sub-strings) and add it to our 2D array
csvData.emplace_back(std::vector<std::string>(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {}));
}
So, why should you use a library for such a simple task that you can do with 2 statements? I personally fail to understand that. Therefore, I find that the advise in the accepted answer is flat wrong. But, to avoid starting religious discussions: This is my very personal humble opinion and everybody can do what he wants.
Please see a complete working example, which solves your problem, with just a few lines of code . . .
#include <iostream>
#include <fstream>
#include <vector>
#include <regex>
const std::string csvFileName{ "r:\\csv.csv" };
const std::regex delimiter{ "," };
int main() {
// Open the file and check, if it could be opened
if (std::ifstream csvFile(csvFileName); csvFile) {
// This is our "2D array string vector" as described in your post
std::vector<std::vector<std::string>> csvData{};
// Read the complete CSV FIle into a 2D vector ----------------------------------------------------
// We will read all lines of the source file with a simple for loop and std::getline
for (std::string line{}; std::getline(csvFile, line); ) {
// We will split the one big string into tokens (sub-strings) and add it to our 2D array
csvData.emplace_back(std::vector<std::string>(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {}));
}
// -------------------------------------------------------------------------------------------------
// This is for summing up values
double DP{}, Dta{}, Dts{};
// Iterate in a simple for loop through all elements of the 2D vector, convert the vlaues to double and sum them up
for (size_t i = 1U; i < csvData.size(); ++i) {
DP += std::stod(csvData[i].at(1));
Dta += std::stod(csvData[i].at(2));
Dts += std::stod(csvData[i].at(3));
}
// Sho the result to the user
std::cout << "\nSums: DP: " << DP << " Dta: " << Dta << " Dts: " << Dts << "\n";
}
else { // In case that we could not open the source file
std::cerr << "\n*** Error. Could not open file " << csvFileName << "\n\n";
}
return 0;
}
But as said, everybdoy can do whatever he wants.