Я не могу поверить, что мы используем библиотеку для такой очень простой вещи, как разбиение std::string
на токены.
C ++ уже давно имеет встроенную и выделенную функциональность, специально разработанную для этого. цель - токенизировать строки (разбивать строки на токены). И поскольку такая простая выделенная функция, предназначенная для этой цели, доступна, ее просто следует использовать. Нет необходимости во внешних библиотеках или сложных конструкциях. Просто используйте std::sregex_token_iterator
.
Это итератор (как и многие другие итераторы), который перебирает токены (подстроки) строки. Итак, что мы хотим.
Затем мы можем использовать конструктор диапазона std::vector
s, чтобы написать что-то простое, например:
std::vector tokens(std::sregex_token_iterator(line.begin(), line.end(), delimiter, -1), {}));
Итак, мы определяем переменную с именем "tokens". "типа std::vector
(с помощью CTAD тип вектора определяется автоматически). Мы используем его конструктор диапазона и предоставляем начальный и конечный итератор. Начальный итератор - это std::sregex_token_iterator
, а конечный итератор - его инициализированный по умолчанию аналог.
Чтобы поместить такой вектор в двухмерный вектор, мы используем функцию внешних векторов emplace_back
и делаем конструкцию на месте для внутреннего вектора.
Таким образом, вы читаете весь CSV-файл с 2 утверждениями
- простой для l oop
- простой переход с
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), {}));
}
Итак, почему вы должны использовать библиотеку для такой простой задачи, которую вы можете выполнить с помощью 2 операторов? Я лично не понимаю этого. Таким образом, я считаю, что совет в принятом ответе совершенно неверный. Но, чтобы не начинать религиозные дискуссии: это мое очень личное скромное мнение, и каждый может делать то, что он хочет.
Пожалуйста, посмотрите полный рабочий пример, который решает вашу проблему, с помощью всего лишь нескольких строк кода. , .
#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;
}
Но, как уже говорилось, каждый может делать все, что захочет.