#include #include #include #include #include #include "CSVParser.h" #include "Exception.h" #include "Parser.h" using namespace std; CSVParser CSVParser::instance {}; CSVParser::CSVParser() { Parser::register_strategy(this); } unsigned int CSVParser::heuristic(FileStrategy & f) { const string content = f.read(); int global_columns = 0; int columns = 1; int rows = 0; int penalty = 1; for (char c : content) { if (c == ',') columns++; if (c == '\n') { rows++; if (global_columns == 0) global_columns = columns; penalty += abs(global_columns - columns); columns = 1; } } if (global_columns == 1) penalty += 1000; return (rows + global_columns) / penalty; } static size_t header_idx(vector header, string field) { auto iter = find(header.begin(), header.end(), field); if (iter == header.end()) throw Exception("CSV file is missing \"%s\" column", field.c_str()); return iter - header.begin(); } void CSVParser::parse(FileStrategy & f, Deserializer & d) { vector> table = {}; istringstream rows(f.read()); string row; while (getline(rows, row)) { // ignore windows line endings if (row.back() == '\r') row.pop_back(); istringstream columns(row); string column; vector table_row = {}; while (getline(columns, column, ',')) { table_row.push_back(column); } table.push_back(table_row); } if (table.size() < 1) throw Exception("not enough data rows in CSV file"); vector table_header = table[0]; table.erase(table.begin()); size_t x_idx = header_idx(table_header, "x"); size_t y_idx = header_idx(table_header, "y"); size_t vx_idx = header_idx(table_header, "vx"); size_t vy_idx = header_idx(table_header, "vy"); for (vector row : table) { d.add_artist({ .x = stof(row[x_idx]), .y = stof(row[y_idx]), .vx = stof(row[vx_idx]), .vy = stof(row[vy_idx]), }); } }