Cod sursa(job #1357419)

Utilizator MrWhiteDELETEME MrWhite Data 23 februarie 2015 22:02:45
Problema Convertor Scor 90
Compilator cpp Status done
Runda rosedu_cdl_2015 Marime 5.23 kb
/**
 * Converts JSON to CSV.
 */

#include <algorithm>
#include <fstream>
#include <iostream>
#include <unordered_map>
#include <stack>
#include <string>
#include <vector>

using namespace std;

typedef pair<string, string> json_field;
typedef vector<json_field> json_entry;

/**
 * Checks if a character is digit.
 *
 * @param ch
 * @return `true` if the given character is digit, `false` otherwise.
 */
bool isdigit(char ch)
{
	return ((ch >= '0') && (ch <= '9'));
}

/**
 * Basic JSON parser working with an array containing multiple dictionaries.
 */
class JsonParser {
public: 

	/**
	 * Parses the JSON data from the stream.
	 *
	 * @param s Source stream. 
	 * @return 
	 */
	bool parse(istream &in, ostream &out);

	/**
	 * Dumps the data in CSV format.
	 *
	 * @param s Destination stream.
	 *
	void dump(ostream &out);
	 */

	/**
	 * Dumps an entry to the output.
	 * I hope this is going to save me some time.
	 *
	 * @see `dump`
	 * @param s Destination stream.
	 * @param entry Source entry.
	 */
	void dumpEntry(ostream &out, json_entry &entry);

private:

	/**
	 * List of possible states of the parser.
	 * They are usually stored in a stack.
	 */
	enum State {

		/** Initial state. */
		STATE_NONE,

		/** In array (expects entry). */
		STATE_IN_ARRAY,

		/** In dictionary (expects field). */
		STATE_IN_DICT,

		/** In dictionary key (expects string). */
		STATE_IN_DICT_KEY,

		/** In a dictionary, expects a value. */
		STATE_IN_DICT_VALUE_TMP,

		/** In dictionary value (expects string). */
		STATE_IN_DICT_VALUE_STR,

		/** In dictionary value (expects integer). */
		STATE_IN_DICT_VALUE_INT,
	};

	/** Stores entries. */
	vector<json_entry> data;
};

int main()
{
	ifstream fin("convertor.in");
	ofstream fout("convertor.out");
	JsonParser jp;
	jp.parse(fin, fout);
	//jp.dump(fout);
	return 0;
}

bool JsonParser::parse(istream &in, ostream &out)
{
	json_entry entry(128);
	json_field field;
	char ch;
	stack<State> state;
	state.push(STATE_NONE);
	while (in >> noskipws >> ch) {
		State current = state.top();
		if (current == STATE_NONE) {
			if (ch == '[') {
				//data.clear();
				state.push(STATE_IN_ARRAY);
			} 
		} else if (current == STATE_IN_ARRAY) {
			if (ch == ']') {
				state.pop();
			} else if (ch == '{') {
				entry.clear();
				state.push(STATE_IN_DICT);
			} else if (ch == ',') {
				// TODO: New entry is coming.
			}
		} else if (current == STATE_IN_DICT) {
			if (ch == '}') {
				//data.push_back(entry);
				dumpEntry(out, entry);
				state.pop();
			} else if (ch == '"') {
				field.first.clear();
				field.second.clear();
				state.push(STATE_IN_DICT_KEY);
			} else if (ch == ':') {
				state.push(STATE_IN_DICT_VALUE_TMP);
			} else if (ch == ',') {
				// TODO: New entry is coming.
			}
		} else if (current == STATE_IN_DICT_KEY) {
			if (ch == '"') {
				// TODO: Escaping.
				state.pop();
			} else {
				field.first += ch;
			}
		} else if (current == STATE_IN_DICT_VALUE_TMP) {
			if (ch == '"') {
				state.top() = STATE_IN_DICT_VALUE_STR;
			} else if (isdigit(ch)) {
				state.top() = STATE_IN_DICT_VALUE_INT;
				field.second += ch;
			}
		} else if (current == STATE_IN_DICT_VALUE_STR) {
			if (ch == '"') {
				entry.push_back(field);
				state.pop();
			} else {
				field.second += ch;
			}
		} else if (current == STATE_IN_DICT_VALUE_INT) {
			if (isdigit(ch)) {
				field.second += ch;
			} else if (ch == ',') {
				entry.push_back(field);
				state.pop();
			} else if (ch == '}') {
				entry.push_back(field);
				//data.push_back(entry);
				dumpEntry(out, entry);
				state.pop();
				state.pop(); // popping STATE_IN_DICT too
			}
		}
	}
	return true; // TODO: Return false on failure.
}

/*
void JsonParser::dump(ostream &out)
{
	// Builds the header (using only the first entry).
	vector<string> header;
	for (json_entry::iterator field = data.begin()->begin(); field != data.begin()->end(); ++field) {
		if (find(header.begin(), header.end(), field->first) == header.end()) {
			header.push_back(field->first);
		}
	}
	// Prints the header.
	for (vector<string>::iterator it = header.begin(); it != header.end(); ++it) {
		out << *it << ',';
	}
	out << '\n';
	// Prints data.
	for (vector<json_entry>::iterator entry = data.begin(); entry != data.end(); ++entry) {
		// TODO: Print fields in order (@see `header`).
		for (json_entry::iterator field = entry->begin(); field != entry->end(); ++field) {
			out << field->second << ',';
		}
		out << '\n';
	}
}
*/

void JsonParser::dumpEntry(ostream &out, json_entry &entry)
{
	static bool isFirst = true;
	if (isFirst) {
		// Builds the header.
		vector<string> header;
		for (json_entry::iterator field = entry.begin(); field != entry.end(); ++field) {
			if (find(header.begin(), header.end(), field->first) == header.end()) {
				header.push_back(field->first);
			}
		}
		// Prints the header.
		for (vector<string>::iterator it = header.begin(); it != header.end(); ++it) {
			out << *it << ',';
		}
		out << '\n';
		isFirst = false;
	}
	// Prints data.
	for (json_entry::iterator field = entry.begin(); field != entry.end(); ++field) {
		out << field->second << ',';
	}
	out << '\n';
}