#include <string>
#include <fstream>
typedef std::vector<std::vector<std::string>> StringListArray; //In some header someplace
//==================================================
//From another file:
//Writes the string out as a file. Returns false if it fails.
bool SaveStringAsFile(const std::string &filename, const std::string &data)
{
//Open the file for writing.
std::ofstream file(filename.c_str(), std::ios_base::out | std::ios_base::trunc);
if(!file)
{
Log::Message(MSG_SOURCE("FileFunctions", Log::Severity::Error)) << "Failed to save '" << Log_HighlightCyan(GetFilenameFromPath(filename)) << "' at " << Log_DisplayPath(filename)
<< " for writing.\nDo I have sufficient privileges? Does the path exist? Is that file already in use?" << Log::FlushStream;
return false;
}
//Write the entire datastring to the file.
file << data;
return true;
}
//==================================================
//From another file:
/*
Loads a CSV (Comma-seperated-value) file and returns the result as a vector of each line of the file.
Each StringList in the vector is a file line, and each string in the StringList is one of the parameters of that line.
Extra whitespace around commas are removed.
When loading, if 'keepRowsSameSize' is true, ensures that every row has the same number of columns, by appending empty cells when needed.
Whitespace, commas, and newlines can be contained in quotation marks to count as a single value.
To escape a quotation mark itself, use two quotation marks in a row: ""
The seperator doesn't have to literally be a comma - tabs or semicolons are also frequently used, but any symbol unlikely to occur normally is fine.
*/
const char CVS_NoWhitespacing = '\0';
StringListArray StringToCSV(const std::string &str, char valueSeperator, char lineSeperator, CharValidatorFunc whitespaceFunc, bool keepRowsSameSize)
{
BUILD_NOTE("This could be better optimized. The quotation mark escaping and replacing is pretty horrible.")
const std::string EscapedQuotationMark = "<quote>";
StringListArray csvFile;
//If the string is empty, just return.
if(str.empty())
return csvFile;
//Keep track of how many columns there are.
size_t maxColumns = 0;
//Replace all two-in-a-row quotation marks with a special symbol.
std::string completeFile = String::ReplaceAll(str, "\"\"", EscapedQuotationMark);
//If the final line ends with a line seperator (like a newline), remove it.
while(completeFile.back() == lineSeperator)
completeFile.pop_back();
StringList lines = String::SeperateAndPreserve(completeFile, lineSeperator, '\"', String::KeepEmptySegments|String::KeepPreservationMarks);
for(const auto &line : lines)
{
StringList values = String::SeperateAndPreserve(line, valueSeperator, '\"', String::KeepEmptySegments);
for(auto &value : values)
{
value = String::RemovePadding(value, whitespaceFunc);
//Add the quotation marks back in.
value = String::ReplaceAll(value, EscapedQuotationMark, "\"");
}
maxColumns = std::max(maxColumns, values.size());
csvFile.emplace_back(std::move(values));
}
//Resize every row to all have the same number of columns.
if(keepRowsSameSize)
{
for(StringList &values : csvFile)
{
values.resize(maxColumns);
}
}
return csvFile;
}
std::string CSVToString(const StringListArray &data, char valueSeperator, char lineSeperator, char whitespace)
{
std::string str;
bool firstLine = true;
for(const auto &line : data)
{
if(!firstLine) str += lineSeperator;
firstLine = false;
bool firstValue = true;
for(auto value : line)
{
if(!firstValue)
{
str += valueSeperator;
if(whitespace != CVS_NoWhitespacing)
{
str += whitespace;
}
}
firstValue = false;
//Replace all quotation marks with two in a row.
value = String::ReplaceAll(value, "\"", "\"\"");
if(String::Contains(value, valueSeperator))
{
str += '\"' + value + '\"';
}
else
{
str += value;
}
}
}
return str;
}
//Loads CSV data from a file. Returns an empty CSVFile if it fails.
StringListArray LoadCSVFile(const std::string &filename, char valueSeperator, char lineSeperator, CharValidatorFunc whitespaceFunc, bool keepRowsSameSize)
{
return StringToCSV(LoadFileAsString(filename), valueSeperator, lineSeperator, whitespaceFunc, keepRowsSameSize);
}
//Saves CSV data to a file. Returns false if it fails.
bool SaveCSVFile(const std::string &filename, const StringListArray &fileData, char valueSeperator, char lineSeperator, char whitespace)
{
return SaveStringAsFile(filename, CSVToString(fileData, valueSeperator, lineSeperator, whitespace));
}