mirror of
https://github.com/pret/pokeplatinum.git
synced 2026-03-21 17:55:13 -05:00
253 lines
6.4 KiB
C++
253 lines
6.4 KiB
C++
#include <sstream>
|
|
#include "CsvFile.h"
|
|
|
|
void CsvFile::ParseRow(std::string &line, std::vector<std::string> &row, bool resize) {
|
|
std::string entry, qbuf;
|
|
bool isQuoted = false;
|
|
int i = 0;
|
|
if (resize) {
|
|
row.clear();
|
|
}
|
|
while (line[0] == '\r') {
|
|
line = line.substr(1);
|
|
}
|
|
while (line[line.size() - 1] == '\r') {
|
|
line = line.substr(0, line.size() - 1);
|
|
}
|
|
std::stringstream line_s(line);
|
|
while (std::getline(line_s, entry, ',')) {
|
|
if (!isQuoted && entry[0] == '"') {
|
|
isQuoted = true;
|
|
entry = entry.substr(1);
|
|
}
|
|
if (isQuoted) {
|
|
if (entry[entry.size() - 1] == '"') {
|
|
isQuoted = false;
|
|
entry = entry.substr(0, entry.size() - 1);
|
|
}
|
|
qbuf += entry;
|
|
if (!isQuoted) {
|
|
if (resize) {
|
|
row.push_back(qbuf);
|
|
} else {
|
|
row[i++] = qbuf;
|
|
}
|
|
qbuf.clear();
|
|
}
|
|
} else {
|
|
if (resize) {
|
|
row.push_back(entry);
|
|
} else {
|
|
row[i++] = entry;
|
|
}
|
|
}
|
|
}
|
|
assert(!isQuoted);
|
|
}
|
|
|
|
void CsvFile::FromFile(const fs::path &filename, bool has_header) {
|
|
std::ifstream handle(filename);
|
|
std::string line;
|
|
std::stringstream filebuf;
|
|
|
|
// Read the whole file at once
|
|
filebuf << handle.rdbuf();
|
|
|
|
// Read the first row
|
|
line = filebuf.str().substr(0, filebuf.str().find_first_of("\r\n"));
|
|
|
|
// Calculate the number of rows
|
|
size_t pos = 0;
|
|
for (
|
|
_nrow = !has_header;
|
|
pos != std::string::npos &&
|
|
(pos = filebuf.str().find_first_of("\r\n", pos), pos != std::string::npos);
|
|
_nrow++
|
|
) {
|
|
pos = filebuf.str().find_first_not_of("\r\n", pos);
|
|
if (pos == std::string::npos) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Calculate the number of columns
|
|
pos = 0;
|
|
for (
|
|
_ncol = 1;
|
|
pos = line.find(',', pos), pos++ != std::string::npos;
|
|
_ncol++
|
|
) {}
|
|
|
|
// Preallocate the rows and colnames
|
|
_rows.resize(_nrow);
|
|
_colnames.resize(_ncol);
|
|
|
|
// Parse the header, or set a dummy header
|
|
if (has_header) {
|
|
ParseRow(line, _colnames, false);
|
|
pos = filebuf.str().find_first_of("\r\n", pos);
|
|
if (pos != std::string::npos) {
|
|
pos = filebuf.str().find_first_not_of("\r\n", pos);
|
|
}
|
|
} else {
|
|
int i = 1;
|
|
for (std::string & name : _colnames) {
|
|
name = "V" + std::to_string(i++);
|
|
}
|
|
pos = 0;
|
|
}
|
|
|
|
// Parse the rows
|
|
size_t last_pos = pos;
|
|
for (
|
|
auto row = _rows.begin();
|
|
row != _rows.end() &&
|
|
(last_pos = pos, last_pos != std::string::npos) &&
|
|
(pos = filebuf.str().find_first_of("\r\n", pos), pos != std::string::npos);
|
|
row++
|
|
) {
|
|
line = filebuf.str().substr(last_pos, pos - last_pos);
|
|
row->resize(_ncol);
|
|
ParseRow(line, *row, false);
|
|
pos = filebuf.str().find_first_not_of("\r\n", pos);
|
|
if (pos == std::string::npos) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CsvFile::GetRow(size_t i, std::vector<std::string> &row) const {
|
|
if (i >= _nrow) {
|
|
row.clear();
|
|
return false;
|
|
} else {
|
|
row = _rows[i];
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool CsvFile::GetCol(size_t i, std::vector<std::string> &col) const {
|
|
if (i >= _ncol) {
|
|
col.clear();
|
|
return false;
|
|
} else {
|
|
int j = 0;
|
|
for (const auto & row : _rows) {
|
|
col[j++] = row[i];
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool CsvFile::GetCol(const std::string &name, std::vector<std::string> &col) const {
|
|
auto it = std::find(_colnames.cbegin(), _colnames.cend(), name);
|
|
if (it != _colnames.cend()) {
|
|
size_t i = it - _colnames.cbegin();
|
|
return GetCol(i, col);
|
|
} else {
|
|
col.clear();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CsvFile::GetCell(size_t row, size_t col, std::string &cell) const {
|
|
if (row >= _nrow || col >= _ncol) {
|
|
cell.clear();
|
|
return false;
|
|
} else {
|
|
cell = _rows[row][col];
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool CsvFile::GetCell(const std::string &colname, size_t row, std::string &cell) const {
|
|
auto it = std::find(_colnames.cbegin(), _colnames.cend(), colname);
|
|
if (it != _colnames.cend()) {
|
|
size_t i = it - _colnames.cbegin();
|
|
return GetCell(row, i, cell);
|
|
} else {
|
|
cell.clear();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CsvFile::SetRow(size_t i, const std::vector<std::string> &row) {
|
|
if (i >= _nrow) {
|
|
return false;
|
|
} else {
|
|
_rows[i] = row;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool CsvFile::SetCol(size_t i, const std::vector<std::string> &col) {
|
|
if (i >= _ncol) {
|
|
return false;
|
|
} else {
|
|
int j = 0;
|
|
for (auto & row : _rows) {
|
|
row[i] = col[j++];
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool CsvFile::SetCol(const std::string &name, const std::vector<std::string> &col) {
|
|
auto it = std::find(_colnames.cbegin(), _colnames.cend(), name);
|
|
if (it != _colnames.cend()) {
|
|
size_t i = it - _colnames.cbegin();
|
|
return SetCol(i, col);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CsvFile::SetCell(size_t row, size_t col, const std::string &cell) {
|
|
if (row >= _nrow || col >= _ncol) {
|
|
return false;
|
|
} else {
|
|
_rows[row][col] = cell;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool CsvFile::SetCell(const std::string &colname, size_t row, const std::string &cell) {
|
|
auto it = std::find(_colnames.cbegin(), _colnames.cend(), colname);
|
|
if (it != _colnames.cend()) {
|
|
size_t i = it - _colnames.cbegin();
|
|
return SetCell(row, i, cell);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void CsvFile::WriteRow(std::ofstream &ofile, const std::vector<std::string> &row) {
|
|
bool first = true;
|
|
for (const auto & entry : row) {
|
|
if (!first) {
|
|
ofile << ',';
|
|
} else {
|
|
first = false;
|
|
}
|
|
bool has_comma = (entry.find(',') != std::string::npos);
|
|
if (has_comma) {
|
|
ofile << '"';
|
|
}
|
|
ofile << entry;
|
|
if (has_comma) {
|
|
ofile << '"';
|
|
}
|
|
}
|
|
ofile << '\n';
|
|
}
|
|
|
|
void CsvFile::ToFile(const fs::path &filename, bool write_header) {
|
|
std::ofstream ofile(filename);
|
|
if (write_header) {
|
|
WriteRow(ofile, _colnames);
|
|
}
|
|
for (auto const & row : _rows) {
|
|
WriteRow(ofile, row);
|
|
}
|
|
}
|