#include <fstream>
#include <string>
#include <vector>
#include <string.h>
using namespace std;
// Citeste un fisier intreg si stocheaza
// tot continutul sau intr-un string,
// pe care il returneaza ulterior.
string read_data( string filename )
{
ifstream f( filename.c_str() );
string s, data;
while( getline( f, s ) )
{
data.append( s );
}
f.close();
return data;
}
// Primeste un string
// care contine date de tip JSON ( in formatul
// specificat in enunt ), si extrage
// un vector de string-uri care contine
// denumirile campurilor din obiectele JSON.
//
// Se parcurge doar primul obiect pentru determinarea
// denumirilor campurilor.
// Se returneaza vectorul extras.
vector<string> extract_keys( string data )
{
bool started_field = false;
vector<string> keys;
string key;
size_t starting_pos;
// Campurile sunt intotdeauna siruri de caractere
// incadrate in ghilimele.
// Astfel, se cauta mereu fie ghilimele, care marcheaza
// inceputul sau sfarsitul unui camp, fie caracterul },
// care marcheaza sfarsitul primului obiect, si finalizarea
// rularii functiei.
size_t found = data.find_first_of( "\"}");
while( data[found] != '}' )
{
// Daca s-au gasit ghilimele, inca nu s-a terminat
// executia structurii 'while'.
// De fiecare data cand se vor gasi ghilimele,
// acestea vor marca fie inceputul, fie sfarsitul unui camp.
//
// Daca ele se gasesc la inceputul campului, se retine pozitia de inceput
// si se cauta in continuare urmatoarele ghilimele.
//
// Daca ele se gasesc la sfarsitul campului, se extrage intr-un string separat.
// care se introduce intr-un vector, subsirul care reprezinta denumirea campului.
//
// Procedeul se repeta pana la sfarsitul primului obiect (pentru ca si urmatoarele
// au tot aceleasi campuri).
if( started_field == false )
{
started_field = true;
starting_pos = found;
}
else
{
started_field = false;
key.assign( data, starting_pos + 1, found - starting_pos - 1 );
keys.push_back( key );
found = data.find_first_of( ",}", found );
if( data[found] == '}' )
{
break;
}
}
found = data.find_first_of( "\"}", found+1 );
}
return keys;
}
// Primeste un string
// care contine date de tip JSON ( in formatul
// specificat in enunt ) si un indice de pozitie
// care marcheaza inceputul unui obiect JSON.
// Functia extrage valorile din fiecare camp al
// obiectului, le stocheaza intr-un vector si le returneaza.
// (fara a mai retine si denumirile campurilor)
vector<string> extract_values( string data, size_t position )
{
vector<string> values;
string value;
// Procedeul pentru extragerea valorilor va fi similar cu cel pentru
// extragerea campurilor, doar ca valorile pot fi si in forma numerica,
// nu numai in forma unui sir de caractere.
//
// Extragerea se incepe de la pozitia trimisa ca parametru
// si continua pana la intalnirea caracterului '}', care marcheaza
// sfarsitul obiectului.
//
// Intotdeauna, valoarea unui camp se gaseste dupa caracterul ':',
// astfel ca de fiecare data se cauta fie acest caracter,
// fie caracterul '}'.
// Cand este gasit caracterul ':', se avanseaza manual
// indicele current_pos pentru a sari peste
// whitespace-ul care s-ar putea gasi intre caracter si valoarea efectiva.
//
// Daca dupa whitespace se intalneste caracterul '"', inseamna ca incepe
// o valoare care este sub forma unui sir de caractere. Se cauta urmatorul
// caracter '"', care marcheaza sfarsitul valorii, si se extrage continutul.
//
// Daca dupa whitespace nu se intalneste caracterul '"', sigur se va intalni o cifra,
// si va fi o valoare numerica.
// In acest caz, se va avansa manual pana la finalul valorii numerice, iar valoarea
// va fi extrasa (dar tot sub forma unui string).
size_t starting_pos = data.find_first_of( ":}", position+1 );
size_t current_pos = starting_pos;
while( data[current_pos] != '}' )
{
while( strchr( "\"0123456789", data[current_pos] ) == 0 )
{
current_pos++;
}
starting_pos = current_pos;
if( data[current_pos] == '"' )
{
current_pos = data.find( '"' , current_pos+1 );
value.assign( data, starting_pos+1, current_pos - starting_pos - 1 );
values.push_back( value );
}
else
{
while( data[current_pos] >= '0' && data[current_pos] <= '9' )
{
current_pos++;
}
value.assign( data, starting_pos, current_pos - starting_pos );
values.push_back( value );
}
current_pos = data.find_first_of( ":}", current_pos );
}
return values;
}
// Primeste un vector de string-uri
// si il scrie intr-un fisier, in continuarea
// datelor deja existente, in format CSV.
void print_csv_vector( vector<string> line, string filename )
{
// Se deschide fisierul dat ca parametru,
// folosindu-se flagurile ios::out si ios::app,
// pentru ca scrierea sa se faca in continuarea
// datelor deja existente.
ofstream g;
g.open( filename.c_str(), ios::out | ios::app );
for( int i = 0; i < line.size(); i++ )
{
g << line[i] << ',';
}
g << endl;
g.close();
}
int main()
{
string data;
vector<string> keys;
vector<string> values;
// Se goleste fortat continutul fisierului convertor.out
ofstream g( "convertor.out" );
g.close();
// Se foloseste functia read_data pentru a citi intreg fisierul
data = read_data( "convertor.in" );
// Se extrag doar denumirile campurilor obiectelor,
// obtinandu-se un vector de string-uri care este
// scris ca antet al fisierului output.
keys = extract_keys( data );
print_csv_vector( keys, "convertor.out" );
// Pentru fiecare obiect, se extrag valorile campurilor,
// fara a se mai retine si denumirile acestora.
// Se afiseaza valorile pe cate o linie noua, si se trece
// la urmatorul obiect dupa fiecare pas, pana cand
// se termina toate obiectele.
size_t position = data.find( '{' );
while( position != string::npos )
{
values = extract_values( data, position );
print_csv_vector( values, "convertor.out" );
position = data.find( '{', position+1 );
}
return 0;
}