140 lines
3.6 KiB
C++
Executable File
140 lines
3.6 KiB
C++
Executable File
#ifndef CSVFILE_HPP
|
|
#define CSVFILE_HPP
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/tokenizer.hpp>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
class CSVFile;
|
|
|
|
inline static CSVFile& endrow(CSVFile& file);
|
|
inline static CSVFile& flush(CSVFile& file);
|
|
|
|
class CSVFile {
|
|
std::ofstream fs_;
|
|
bool is_first_;
|
|
const std::string separator_;
|
|
const std::string escape_seq_;
|
|
const std::string special_chars_;
|
|
|
|
public:
|
|
CSVFile(const std::filesystem::path& filename,
|
|
const bool& overwrite,
|
|
const std::string separator = ",")
|
|
: fs_(),
|
|
is_first_(true),
|
|
separator_(separator),
|
|
escape_seq_("\""),
|
|
special_chars_("\"") {
|
|
fs_.exceptions(std::ios::failbit | std::ios::badbit);
|
|
if (filename.empty()) {
|
|
fs_.copyfmt(std::cout);
|
|
fs_.clear(std::cout.rdstate());
|
|
fs_.basic_ios<char>::rdbuf(std::cout.rdbuf());
|
|
} else {
|
|
if (!std::filesystem::exists(filename)) {
|
|
std::ofstream outfile(filename);
|
|
outfile.close();
|
|
}
|
|
overwrite ? fs_.open(filename, std::ios::trunc)
|
|
: fs_.open(filename, std::ios::app);
|
|
}
|
|
}
|
|
|
|
~CSVFile() {
|
|
flush();
|
|
fs_.close();
|
|
}
|
|
|
|
void flush() { fs_.flush(); }
|
|
|
|
void endrow() {
|
|
fs_ << std::endl;
|
|
is_first_ = true;
|
|
}
|
|
|
|
CSVFile& operator<<(CSVFile& (*val)(CSVFile&)) { return val(*this); }
|
|
|
|
CSVFile& operator<<(const char* val) { return write(escape(val)); }
|
|
|
|
CSVFile& operator<<(const std::string& val) { return write(escape(val)); }
|
|
|
|
template <typename T>
|
|
CSVFile& operator<<(const T& val) {
|
|
return write(val);
|
|
}
|
|
|
|
static std::vector<std::vector<std::string>> parse(
|
|
const std::filesystem::path& csvFilepath) {
|
|
std::vector<std::vector<std::string>> resultCSV;
|
|
if (!std::filesystem::exists(csvFilepath)) {
|
|
std::cerr << "The file does not exist:" << csvFilepath.string()
|
|
<< std::endl;
|
|
return resultCSV;
|
|
}
|
|
|
|
std::ifstream inputfile(csvFilepath.string().c_str());
|
|
if (!inputfile.is_open()) {
|
|
std::cerr << "Can't open file:" << csvFilepath.string() << std::endl;
|
|
return resultCSV;
|
|
}
|
|
std::vector<std::string> row;
|
|
std::string line;
|
|
using Tokenizer = boost::tokenizer<boost::escaped_list_separator<char>>;
|
|
while (std::getline(inputfile, line)) {
|
|
Tokenizer tokenizer(line);
|
|
const int numOfCols = std::distance(tokenizer.begin(), tokenizer.end());
|
|
row.resize(numOfCols);
|
|
std::copy(tokenizer.begin(), tokenizer.end(), row.begin());
|
|
// std::transform(tokenizer.begin(), tokenizer.end(),
|
|
// row.begin(), [](const std::string &el) {
|
|
// return boost::lexical_cast<T>(el);
|
|
// });
|
|
resultCSV.push_back(row);
|
|
}
|
|
|
|
return resultCSV;
|
|
}
|
|
|
|
private:
|
|
template <typename T>
|
|
CSVFile& write(const T& val) {
|
|
if (!is_first_) {
|
|
fs_ << separator_;
|
|
} else {
|
|
is_first_ = false;
|
|
}
|
|
fs_ << val;
|
|
return *this;
|
|
}
|
|
|
|
std::string escape(const std::string& val) {
|
|
std::ostringstream result;
|
|
result << '"';
|
|
std::string::size_type to, from = 0u, len = val.length();
|
|
while (from < len && std::string::npos !=
|
|
(to = val.find_first_of(special_chars_, from))) {
|
|
result << val.substr(from, to - from) << escape_seq_ << val[to];
|
|
from = to + 1;
|
|
}
|
|
result << val.substr(from) << '"';
|
|
return result.str();
|
|
}
|
|
};
|
|
|
|
inline static CSVFile& endrow(CSVFile& file) {
|
|
file.endrow();
|
|
return file;
|
|
}
|
|
|
|
inline static CSVFile& flush(CSVFile& file) {
|
|
file.flush();
|
|
return file;
|
|
}
|
|
|
|
#endif // CSVFILE_HPP
|