Никто не будет заинтересован в следующем, так как этот ответ дается через 5 дней после того, как вопрос задан.
Кроме того, OP является новым для C ++, и не будет его понимать. Но поскольку эти вопросы помечены C ++, а другие ответы очень C -Style-i sh, я хочу показать здесь более современное решение C ++ с объектно-ориентированным подходом.
И Я везде вижу злоупотребление std::getline
для разделения строк, что невероятно, поскольку существуют специальные функции для разделения строк. Предполагаемое использование для std::getline
- «получить линию» из потока. Как следует из названия. Люди возятся с этой функцией и ищут разделители и так далее, но, по моему скромному мнению, мы не должны этого делать.
Уже около 10 лет у нас есть специальная специальная функция C ++ для разбиения строк на токены. , специально разработанный для этой цели. std::sregex_token_iterator
. И поскольку у нас есть такая выделенная функция, мы должны просто использовать ее.
Идея в том, что это концепция итератора. В C ++ у нас есть много контейнеров и всегда итераторов, чтобы перебирать похожие элементы в этих контейнерах. И строка с похожими элементами (токенами), разделенными разделителем, также может рассматриваться как такой контейнер. А с помощью std::sregex:token_iterator
мы можем перебирать элементы / токены / подстроки строки, эффективно разбивая ее на части.
Этот итератор очень мощный, и вы можете делать с ним гораздо более сложные вещи. Но это слишком много для здесь. Важно то, что разбиение строки на токены - это одна строка. Например, определение переменной с использованием конструктора диапазона для итерации по токенам. См. Например:
// The delimiter
const std::regex delimiter{ "," };
// Test data
std::string csvData("d1,d2,d3,d4,d5");
// Split the string
std::vector<std::string> tokens(std::sregex_token_iterator(csvData.begin(), csvData.end(), delimiter, -1), {});
Ant, так как это итератор, вы можете использовать его со многими алгоритмами. Вы должны действительно изучить и использовать это. И для всех этих людей, имеющих большие опасения по поводу эффективности, обратите внимание, что в 90% случаев будет проанализировано только несколько строк. Нет проблем.
Итак, дальше. У нас есть объектно-ориентированный язык. Итак, давайте используем его и определяем класс для ваших данных с упомянутыми вами членами данных, а также дополнительными функциями или операторами для работы с этими элементами данных. Только класс должен знать о его внутренностях. Снаружи мы хотим использовать его, не зная реализации.
В приведенном ниже примере экстрактор и iserter будут перезаписаны, чтобы включить потоковые операции ввода-вывода. В экстракторе мы также будем использовать функцию regex
и точно проверим, соответствует ли строка ввода нашим ожиданиям. Для этого мы используем std::regex
, который точно определяет шаблон данных в строке CSV. Затем, если мы нашли совпадение, мы можем использовать данные. Таким образом, это не только разделение строки, но и проверка правильности ввода. Функция для этого: std::regex_match
.
И, если вы посмотрите на main
, чтение и синтаксический анализ всех данных CSV будут однострочными. То же самое для вывода данных.
Пожалуйста, смотрите:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <regex>
const std::regex re{R"(^\s*?(\b\w+)\s*?,\s*?(\d+\.\d+)\s*?,\s*?(\d+)\s*?$)"};
// Proxy class for easy input and output
struct MyData {
std::string name{};
double price{};
long quantity{};
// Overwrite extractor operator for easier input
friend std::istream& operator >> (std::istream& is, MyData& md) {
// Read a complete line from your CSV file
if (std::string line{}; std::getline(is, line)) {
// Check, if the input string matches to pour expectation, so split and validate
if (std::smatch match{}; regex_match(line, match, re)) {
// Match is perfect. Assign the values to our internal data members
md.name = match[1]; md.price = std::stod(match[2]); md.quantity = std::stol(match[3]);
}
else // No match. Set everything to default
md = {};
}
return is;
}
// Simple output of our data members
friend std::ostream& operator << (std::ostream& os, const MyData& md) {
return os << "Name: " << md.name << "\t\tPrice: " << md.price << "\tQuantity: " << md.quantity;
}
};
int main() {
// Open the csv File and check, if it could be opened and everything is ok
if (std::ifstream csvStream("r:\\antiquelist.txt"); csvStream) {
// Read and parse the complete source file
std::vector myData(std::istream_iterator<MyData>(csvStream), {});
// Show complete result to user
std::copy(myData.begin(), myData.end(), std::ostream_iterator<MyData>(std::cout, "\n"));
}
else {
std::cerr << "\n*** Error: Could not open input file\n";
}
return 0;
}
Пожалуйста, посмотрите здесь , чтобы лучше понять регулярное выражение
Как жаль что никто не будет читать это. , .