Introduction:
csvparser is a simple c++ program. It can load, save and modify Microsoft Excel friendly CSV files.
It supports quotation marks, line breaks and commas in cell values.
It uses std::map to store data. It supports up to 2^32 columns and rows.
About:
csvparser by Hamid Soltani. (gmail: hsoltanim)
Code:
Download csvparser.cpp
/****************************************************************************
Introduction:
csvdata is a simple c++ class.
It can load, save and modify Microsoft Excel friendly CSV files.
It supports quotation marks, line breaks and commas in cell values.
It uses std::map to store data. It supports up to 2^32 columns and rows.
Usage:
Create a csvdata:
csvdata csv;
Load a CSV file:
csv.LoadFile("filename.csv");
Keep current data and load a CSV file:
csv.LoadFile("filename.csv",false);
Save to a CSV file:
csv.SaveFile("filename.csv");
Assign a value to cell:
csv.SetCell(row, column, value);
Get cell value:
value = csv.GetCell(row, column);
Get cell value as a double:
check=GetCellDouble(row, column, &x)
Erase a cell:
csv.EraseCell(row, column); // same as SetCell(row, column, "");
Check if a cell has value and assign it to a string:
check = csv.Find(row, column, &str);
Get lower and upper bounds:
check = csv.LBElem(&row, &column, &str);
check = csv.UBElem(&row, &column, &str);
Search for a value from position row, column:
check = csv.Search(value, &row, &column);
Search for a value from position 0, 0:
check = csv.Search(value, &row, &column, true);
Iteration:
check = csv.BeginIter(&it);
check = csv.NextIter(&it);
csv.GetIter(it, &row, &column, &str);
Clear data:
csv.Clear();
() Operator (read and write):
csv(row, column)
Convert a string to a safe CSV string:
value = SafeStr(str);
Convert a CSV string to a primary form:
value = PrimaryStr(str);
csvdata version 1.3 by Hamid Soltani. (gmail: hsoltanim)
https://csvparser.github.io/
Last modified: Aug. 2016.
*****************************************************************************/
#include "stdafx.h"
#include < map >
#include < fstream >
#include < string >
// header files used by main() function
#include < iostream >
#include < stdlib.h >
#include < stdio.h >
#include < ctime >
using LI = unsigned long int;
using LLI = unsigned long long int;
union _I {
LLI index;
struct {
LI column;
LI row;
} at;
};
/****************************************************************************/
class csvdata
{
private:
std::map< LLI, std::string > csv_map;
LLI _index(LI row, LI column);
LI _row(LLI index);
LI _column(LLI index);
public:
csvdata();
~csvdata();
int LoadFile(const char* filename, bool isclear = true);
int SaveFile(const char* filename);
int EraseCell(LI row, LI column);
int SetCell(LI row, LI column, const std::string& value);
std::string GetCell(LI row, LI column);
bool GetCellDouble(LI row, LI column, double& x);
bool Search(const std::string& value, LI& row, LI& column, bool is_reset = false);
bool Find(LI row, LI column, std::string& value);
bool LBElem(LI& row, LI& column, std::string& value);
bool UBElem(LI& row, LI& column, std::string& value);
bool BeginIter(std::map< LLI, std::string >::iterator& it);
bool NextIter(std::map< LLI, std::string >::iterator& it);
void GetIter(std::map< LLI, std::string >::iterator& it, LI& row, LI& column, std::string& value);
int Clear();
std::string& operator() (const LI row, const LI column);
};
const std::string PrimaryStr(const std::string& s);
const std::string SafeStr(const std::string& s);
bool StrDouble(const std::string s, double& x);
using namespace std;
/****************************************************************************/
LLI csvdata::_index(LI row, LI column)
{
_I i;
i.at.row = row;
i.at.column = column;
return i.index;
}
LI csvdata::_row(LLI index)
{
_I i;
i.index = index;
return i.at.row;
}
LI csvdata::_column(LLI index)
{
_I i;
i.index = index;
return i.at.column;
}
csvdata::csvdata()
{
}
csvdata::~csvdata()
{
Clear();
}
int csvdata::LoadFile(const char* filename, bool isclear)
{
if (isclear)
Clear();
LI row = 0;
LI column = 0;
string cell = "";
bool qflag = false;
char c;
ifstream is(filename);
if (!is.good())
return 1;
while (is.get(c))
{
if (qflag)
{
if (c == '"')
{
if (is.peek() == '"')
{
is.get(c);
cell += c;
}
else
qflag = false;
}
else
cell += c;
}
else
{
if ((c == '"') && (cell.length() == 0))
qflag = true;
else if (c == ',')
{
if (cell.length() > 0)
{
csv_map[_index(row, column)] = cell;
cell = "";
}
column++;
}
else if (c == '\n')
{
if (cell.length() > 0)
{
csv_map[_index(row, column)] = cell;
cell = "";
}
row++;
column = 0;
}
else if (c >= 32)
cell += c;
}
}
if (cell.length() > 0)
csv_map[_index(row, column)] = cell;
is.close();
return 0;
}
int csvdata::SaveFile(const char* filename)
{
LI row = 0;
LI column = 0;
ofstream os(filename);
if (!os.good())
{
return 1;
}
for (auto it : csv_map)
{
LLI ind = it.first;
if (row < _row(ind))
{
while (row<_row(ind))
{
os << "\n";
row++;
}
column = 0;
}
while (column < _column(ind))
{
os << ",";
column++;
}
os << SafeStr(it.second).c_str();
}
os << "\n";
os.close();
return 0;
}
int csvdata::EraseCell(LI row, LI column)
{
csv_map.erase(_index(row, column));
return 0;
}
int csvdata::SetCell(LI row, LI column, const string& value)
{
unsigned int len = (unsigned)value.length();
if (len == 0)
{
csv_map.erase(_index(row, column));
return 1;
}
else
{
csv_map[_index(row, column)] = value;
return 0;
}
}
string csvdata::GetCell(LI row, LI column)
{
auto it = csv_map.find(_index(row, column));
if (it != csv_map.end())
return it->second;
else
return "";
}
bool csvdata::GetCellDouble(LI row, LI column, double& x)
{
auto it = csv_map.find(_index(row, column));
if (it != csv_map.end())
{
return StrDouble(it->second, x);
}
else
return false;
}
bool csvdata::Search(const string& value, LI& row, LI& column, bool is_reset)
{
if (is_reset)
{
row = 0;
column = 0;
}
for (map< LLI, string >::iterator it = csv_map.lower_bound(_index(row, column)); it != csv_map.end(); ++it)
{
if (strcmp(it->second.c_str(), value.c_str()) == 0)
{
LLI ind = it->first;
row = _row(ind);
column = _column(ind);
return true;
}
}
return false;
}
bool csvdata::Find(LI row, LI column, string& value)
{
map< LLI, string >::iterator it = csv_map.find(_index(row, column));
if (it != csv_map.end())
{
value = it->second;
return true;
}
else
{
return false;
}
}
bool csvdata::LBElem(LI& row, LI& column, string& value)
{
map< LLI, string >::iterator it = csv_map.lower_bound(_index(row, column));
if (it != csv_map.end())
{
LLI ind = it->first;
row = _row(ind);
column = _column(ind);
value = it->second;
return true;
}
else
{
return false;
}
}
bool csvdata::UBElem(LI& row, LI& column, string& value)
{
map< LLI, string >::iterator it = csv_map.upper_bound(_index(row, column));
if (it != csv_map.end())
{
LLI ind = it->first;
row = _row(ind);
column = _column(ind);
value = it->second;
return true;
}
else
{
return false;
}
}
bool csvdata::BeginIter(map< LLI, string >::iterator& it)
{
it = csv_map.begin();
return (it != csv_map.end());
}
bool csvdata::NextIter(map< LLI, string >::iterator& it)
{
it++;
return (it != csv_map.end());
}
void csvdata::GetIter(map< LLI, string >::iterator& it, LI& row, LI& column, string& value)
{
row = _row(it->first);
column = _column(it->first);
value = it->second;
}
int csvdata::Clear()
{
csv_map.clear();
return 0;
}
string& csvdata::operator() (const LI row, const LI column)
{
return csv_map[_index(row, column)];
}
/****************************************************************************/
const string PrimaryStr(const string& s)
{
string t;
unsigned int len = (unsigned)s.length();
if ((len>0) && (s[0] == '"') && (s[len - 1] == '"'))
for (unsigned int i = 1; i < len - 1;i++)
{
t += s[i];
if ((s[i] == '"') && (s[i + 1] == '"'))
i++;
}
else
t = s;
return t;
}
const string SafeStr(const string& s)
{
string t;
unsigned int len = (unsigned)s.length();
if ((s[0] == '"') && (s[len - 1] == '"'))
{
t = "\"";
for (unsigned int i = 1; i < len - 1;i++)
if (s[i] == '"')
{
t += "\"\"";
if (s[i + 1] == '"')
i++;
}
else
{
t += s[i];
}
t += "\"";
}
else
{
unsigned int i = 0;
bool qneed = (s[0] == '\"');
while ((!qneed) && (i < len))
{
qneed = ((s[i] == ',') || (s[i] == '\n'));
i++;
}
if (qneed)
{
t = "\"";
for (unsigned int i = 0; i < len;i++)
{
if (s[i] == '"')
t += "\"\"";
else
t += s[i];
}
t += "\"";
}
else
{
t = s;
}
}
return t;
}
bool StrDouble(const string s, double& x)
{
double d;
try {
d = stod(s);
}
catch (const invalid_argument&) {
return false;
}
catch (const out_of_range&) {
return false;
}
x = d;
return true;
}
// example of using csvdata class
int main()
{
csvdata csv;
// assigning some data
csv.SetCell(0, 0, "Multiplication Table:");
for (int i = 1;i < 10;i++)
for (int j = 1;j < 10;j++)
csv.SetCell(i, j, to_string(i*j));
csv.SetCell(12, 0, "Some Tests:");
csv.SetCell(13, 1, "Comma, Test 1");
csv.SetCell(13, 2, ",Comma Test 2");
csv.SetCell(13, 3, "\"Comma Test 3,\"");
csv.SetCell(13, 4, "\"Comma, Test 4\"");
csv.SetCell(13, 5, "\",Comma Test 5\"");
csv.SetCell(13, 6, "Comma Test 6,");
csv.SetCell(14, 1, "Qutation\" Test 1");
csv.SetCell(14, 2, "\"Qutation Test 2");
csv.SetCell(14, 3, "Qutation Test 3\"");
csv.SetCell(14, 4, "\"Qutation\" Test 4\"");
csv.SetCell(14, 5, "\"\"Qutation Test 5\"");
csv.SetCell(14, 6, "\"Qutation Test 6\"\"");
csv.SetCell(15, 1, "Line break\n Test 1");
csv.SetCell(15, 2, "\nLine break Test 2");
csv.SetCell(15, 3, "Line break Test 3\n");
csv.SetCell(15, 4, "\"Line break\n Test 4\"");
csv.SetCell(15, 5, "\"\nLine break Test 5\"");
csv.SetCell(15, 6, "\"Line break Test 6\n\"");
csv.SetCell(16, 1, "Old Value");
csv.SetCell(16, 1, "New Value");
csv.SetCell(16, 2, "To be Erased!");
csv(20, 1) = "By operator!";
//save and load files
csv.SaveFile("1.csv");
csv.Clear();
csv.SetCell(10, 8, "Date:");
csv.SetCell(18, 8, "Date:");
csv.SaveFile("2.csv");
csv.LoadFile("1.csv");
csv.LoadFile("2.csv", false);
csv.EraseCell(16, 2);
// assign current date after cell "Date:"
struct tm newtime;
__time64_t long_time;
char timebuf[40];
_time64(&long_time);
_localtime64_s(&newtime, &long_time);
strftime(timebuf, 40, "%m/%d/%Y %H:%M:%S", &newtime);
LI row = 0;
LI column = 0;
string value;
while (csv.Search("Date:", row, column))
{
csv.SetCell(row, column + 1, timebuf);
column++;
}
// display method 1
row = 0;
column = 0;
while (csv.LBElem(row, column, value))
{
cout << row << ", " << column << ": " << value.c_str() << endl;
column++;
}
// display method 2
map< LLI, string >::iterator it;
for (bool csvchk = csv.BeginIter(it);csvchk;csvchk = csv.NextIter(it))
{
csv.GetIter(it, row, column, value);
cout << row << ", " << column << ": " << value.c_str() << endl;
}
csv.SaveFile("3.csv");
puts("Press Enter to exit...\n");
getchar();
return 0;
}