Ok let's say I have a text file:

``````(0,0) = 1.0	(0,1) = 2.0	(0,2) = 3.0
(1,0) = g	(1,2) = 2.0
(2,2) = hi there	(2,8) = ee
(5,4) = e
(10,1) = g``````

Where the each part of the line is delimited by a tab.

And the coords (x,y) represents the row and column in an excel file.

so (1,2) = 2.0 would mean put the value 2.0 on row 1 column 2 in the excel file. (or i should say row 2 column 3 because it starts at (0,0) but you get what I mean.)

How would I generate a csv file

``````1,2,3,,,,,,
g,,2,,,,,,
,,hi there,,,,,,ee

,,,,e,,,,

,g,,,,,,,``````

Note there are 8 commas per line because that is the maximum column value (highlighted in red).

Sample code would be great.

## All 9 Replies

Do you think that this converter is an one-screen-page program?

Do you think that this converter is an one-screen-page program?

What?

>How would I generate a csv file
The first thing that comes to mind is a sparse matrix to store the coordinates and value. Then when you iterate through the matrix, you can fill the gaps with empty fields and blank lines as appropriate, and really all you need to search for is the maximum number of fields:

``````int max_fields = 0;

// Find the largest column value
for ( int i = 0; i < matrix.size(); i++ ) {
for ( int j = 0; j < matrix[i].size(); j++ ) {
if ( matrix[i][j].column > max_fields )
max_fields = matrix[i][j].column;
}
}

int row = 0;

// Write out the CSV format
for ( int i = 0; i < matrix.size(); i++ ) {
while ( row != matrix[i][0].row ) {
new_csv_row();
++row;
}

int k = 0;

for ( int j = 0; j <= max_fields; j++ ) {
if ( k < matrix[i].size() && j == matrix[i][k].column )
put_csv_field ( matrix[i][j].value );
else
put_csv_field ( "" );
}

new_csv_row();
}``````

Simple and effective.

As far as I know the empty CSV line is ",,,,,,,,".
With minimal syntax check up:

``````/* Includes:
#include <cstring>
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
*/
struct Tokenizer
{
public:
Tokenizer(char delim):chdelim(delim)
{}
void setDelim(char delim);
void clear() { token.clear(); }
int parse(const char* ptext);
int parse(const std::string& s) { return parse(s.c_str()); }
std::vector<std::string> token;
char chdelim;
};

int Tokenizer::parse(const char* ptext)
{
clear();
if (!ptext)
return 0;
std::string tok;
const char* p = ptext;
const char* q, *qq;
const char* qend = ptext + std::strlen(ptext);
bool goon = true;

for (p = ptext; goon ;p = q+1)
{
q = std::strchr(p,chdelim);
if (!q)
{
q = qend;
goon = false;
}
while (p < q && *p == ' ')
++p;
for (qq = q - 1; qq > p && *qq == ' '; --qq)
;
tok.assign(p,qq-p+1);
token.push_back(tok);
}
return size();
}

struct RowCol
{
RowCol():x(0),y(0) {}
RowCol& set(int i, int j)
{
x = i; y = j;
return *this;
}
bool parse(const char* pxy);
bool parse(const std::string& sxy)
{
return parse(sxy.c_str());
}
int x, y;
};

bool operator <(const RowCol& a,const RowCol& b)
{
return a.x < b.x?true:a.x > b.x?false:a.y < b.y;
}

bool RowCol::parse(const char* pxy)
{
if (!pxy || *pxy != '(')
return false;
Tokenizer t(',');
t.parse(pxy+1);
if (t.size() != 2)
return false;
x = atoi(pxy+1);
y = atoi(t.token[1].c_str());
return true;
}

typedef std::map<RowCol,std::string> Map;
typedef Map::const_iterator Iter;
typedef std::pair<RowCol,std::string> V;

void CsvOut(const Map& m, int width, std::ostream& os)
{
int xcurr = 0, ycurr = 0;

for (Iter p = m.begin(); p != m.end(); ++p)
{
const RowCol& cell = (*p).first;
if (cell.x != xcurr)
{
while (xcurr < cell.x)
{
for (int j = ycurr; j < width-1; ++j)
os << ',';
os << '\n';
++xcurr;
ycurr = 0;
}
}
if (ycurr < cell.y)
{
while (ycurr < cell.y)
++ycurr,os << ',';
}
else if (cell.y)
os << ',';
os << (*p).second;
}
if (ycurr)
{
while (++ycurr < width)
os << ',';
os << '\n';
}
os.flush();
}

int CsvConverter(std::ostream& os, std::istream& is)
{
Map m;
RowCol xy;
Tokenizer t('\t');
Tokenizer u('=');
std::string line;

while (std::getline(is,line))
{
t.parse(line);
for (int i = 0; i < t.size(); ++i)
{
u.parse(t.token[i]);
if (u.size() == 2)
{
xy.parse(u.token[0]);
m.insert(V(xy,u.token[1]));
}
}
}
CsvOut(m,9,os);
return m.size();
}

const char* pTest =
"(0,0) = 1.0\t(0,1) = 2.0\t(0,2) = 3.0\n"
"(1,0) = g\t(1,2) = 2.0\n"
"(2,2) = hi there\t(2,8) = ee\n"
"(5,4) = e\n"
"(10,1) = g\n"
;
int main(int argc, char* argv[])
{
std::istringstream test(pTest);
CsvConverter(std::cout,test);

return 0;
}
/* Output:
1.0,2.0,3.0,,,,,,
g,,2.0,,,,,,
,,hi there,,,,,,ee
,,,,,,,,
,,,,,,,,
,,,,e,,,,
,,,,,,,,
,,,,,,,,
,,,,,,,,
,,,,,,,,
,g,,,,,,,
*/``````
commented: Interesting, though I never thought that you of all people would use structs and methods together! @_@ +4

If everyone is going to give iamthwee free code, I might as well give my 2 cents :D

- I went for excel, where a CSV is separated by ';' instead of ','
- an empty line is a '\n'
- there's no need to fill every line with semicolon's when there's no more data for that line
- your data never starts with a '(' (easy to change)
- the cell-coordinates will always be in ascending order in your input file.

Here's the code. It can be done better, but I don't have any time left to change/improve it :)

``````#include <iostream>
#include <string>
#include <map>
#include <fstream>
#include <sstream>

using namespace std;

int StringToInT(string str)
{
int number;
istringstream conv(str);
conv >> number;
return number;
}
int main()
{
ifstream in("c:\\input.txt");
if (!in.is_open())
{
cout << "open failed";
return 1;
}

// put everything in a map, discarding whitespaces
int counter = -1; //assuming '(' is first in file
string buffer;
map<int ,string> data;
while (in >> buffer)
{
if (buffer[0] == '(') counter++;
data[counter] += buffer + " ";
}

// find max col number
int maxcols = 0;
for (unsigned int i = 0; i < data.size(); i++)
{
string max = data[i].substr(data[i].find_first_of(",")+1
,data[i].find_first_of(")")- data[i].find_first_of(",")-1);
int number = StringToInT(max);
if (number > maxcols) maxcols = number;
}
//write everything back
ofstream out("c:\\output.csv");
if (!out.is_open())
{
cout << "open failed";
return 1;
}
int current_row =0;
for (unsigned int j = 0; j < data.size(); j++)
{
string srow = data[j].substr(data[j].find_first_of("(")+1
,data[j].find_first_of(",")- data[j].find_first_of("(")-1);

while (StringToInT(srow) != current_row)
{
out << "\n";
current_row++;
}
for (int k = 0; k <=maxcols; k++)
{
string scol = data[j].substr(data[j].find_first_of(",")+1
,data[j].find_first_of(")")-
data[j].find_first_of(",")-1);
if (StringToInT(scol) == k)
{
out << data[j].substr(data[j].find_first_of("=")
+2,string::npos);
break;
}
else
out << ";";
}
}
return 0;
}``````

Output:

``````1.0 ;2.0 ;;3.0
g ;;2.0
;;hi there ;;;;;;;;ee

;;;;e

;g``````

(this is not the CSV standard, but works fine(better) in Excel)

Come to think of it, my code adds an additional [space] to the data, don't have time to fix it now, sorry

Change of plan, I'm using a completely different file now to parse through.

Change of plan, I'm using a completely different file now to parse through.

What? ;)

Were you just screwing with us, iamthwee? :icon_rolleyes:

Were you just screwing with us, iamthwee? :icon_rolleyes:

No of course not. I am a very serious person. You have hurt my feelings.

Basically I am using another program/script which reads an excel file and dumps out the values.
The reason I am using this other script is because the values are more reliable and require less code for me to tamper with.

I am trying to write a free excel to tab/csv convertor.

To see this in context you might want to look at: