TU-Programmieren_2/lab3/modules/iue-io/csv.hpp
2025-04-09 10:22:44 +02:00

99 lines
3.1 KiB
C++

#pragma once
#include <filesystem> // std::filesystem::path
#include <fstream> // std::ofstream|ifstream
#include <iomanip> // std::scientifc|setprecision
#include <iostream> // std::cout|endl
#include <limits> // std::numeric_limits
#include <sstream> // std::istringstream
#include <string> // std::string
#include <vector> // std::vector
namespace iue::io {
/// @brief Writes a numeric values to a file using a csv-format
/// @param filepath file to be written including the desired extension
/// @param table table with the rows to be written
/// @param del delimiter between individual values
/// @param header informative comment in the output file
/// @param comments character signalling that a line is a comment (if used as first character of the line )
inline void savetxt(std::filesystem::path filepath, const std::vector<std::vector<double>>& table, char del = ' ',
std::string header = "", char comments = '#') {
// setup row writer callable
auto serialize = [&del](const std::vector<double>& row) -> std::string {
std::ostringstream oss;
for (auto iter = row.begin(); iter != std::prev(row.end()); ++iter)
oss << std::scientific << std::setprecision(18) << *iter << del;
oss << std::scientific << std::setprecision(18) << *std::prev(row.end()); // avoid trailing return
oss << std::endl;
return oss.str();
};
// check if data is present
if (table.empty())
return;
// open file
std::ofstream stream;
stream.exceptions(std::ifstream::badbit);
stream.open(filepath);
// write header lines
if (!header.empty()) {
std::string line;
std::istringstream iss(header);
while (std::getline(iss, line)) {
stream << comments << ' ' << line << std::endl;
}
}
// write data
for (const auto& row : table)
stream << serialize(row);
}
/// @brief Read numeric values stored in a csv-format
/// @param filepath input file containing the numeric values
/// @param del delimiter between individual values
/// @param comments character signalling that a line is a comment (if used as first character of the line )
/// @return table which was read
inline std::vector<std::vector<double>> loadtxt(std::filesystem::path filepath, char del = ' ', char comments = '#') {
// setup row parser callable
auto deserialize = [&del](const std::string& line) -> std::vector<double> {
std::vector<double> res;
std::stringstream stream(line);
std::string item;
while (std::getline(stream, item, del)) {
std::stringstream ss(item);
ss.exceptions(std::ios::failbit);
auto value = std::numeric_limits<double>::quiet_NaN();
ss >> value;
res.push_back(value);
}
return res;
};
// setup table
std::vector<std::vector<double>> table;
// open file
std::ifstream stream;
stream.exceptions(std::ifstream::badbit);
stream.open(filepath);
// read from stream row-by-row
std::string line;
// read line to row vectors
while (std::getline(stream, line)) {
if (line.front() == comments)
continue;
table.push_back(deserialize(line));
}
return table;
}
} // namespace iue::io