Cod sursa(job #1357594)

Utilizator MrWhiteDELETEME MrWhite Data 23 februarie 2015 23:39:44
Problema Convertor Scor 90
Compilator cpp Status done
Runda rosedu_cdl_2015 Marime 5.35 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_dictionary;

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

/**
 * Basic JSON object.
 */
class Json {
public:

	/**
	 * Adds a dictionary in the `data` vector.
	 *
	 * @param dict
	 * @param out Actually, no dictionary is being added to the `data` vector.
	 *            The dictionary is printed to the output stream as soon as
	 *            possible. I did this to save some time. Please, forgive me.
	 */
	void addDictionary(json_dictionary &dict, ostream &out);

	/**
	 * Prints the JSON file in CSV format to the output stream.
	 *
	 * @param out
	 */
	void dump(ostream &out);

private:

	/**
	 * Stores dictionaries.
	 */
	vector<json_dictionary> data;

};

/**
 * Basic JSON parser.
 */
class JsonParser {
public: 

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

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 value. */
		STATE_IN_DICT_VALUE,

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

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

int main()
{
	ifstream fin("convertor.in");
	ofstream fout("convertor.out");
	JsonParser jp;
	Json *json = jp.parse(fin, fout);
	return 0;
}

Json* JsonParser::parse(istream &in, ostream &out)
{
	Json *json = new Json;
	json_dictionary entry;
	char ch, key[128], value[1024];
	int keyLen = 0, valueLen = 0;
	stack<State> state;
	state.push(STATE_NONE);
	while (state.size()) {
		in >> noskipws >> ch;
		State current = state.top();
		if (current == STATE_NONE) {
			if (ch == '[') {
				state.top() = 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 == '}') {
				json->addDictionary(entry, out);
				state.pop();
			} else if (ch == '"') {
				keyLen = 0;
				valueLen = 0;
				while (in >> noskipws >> ch) {
					if (ch == '"') {
						break;
					}
					key[keyLen++] = ch;
				}
			} else if (ch == ':') {
				while (in >> noskipws >> ch) {
					if (ch == '"') {
						current = STATE_IN_DICT_VALUE_STR;
						break;
					} else if (isdigit(ch)) {
						current = STATE_IN_DICT_VALUE_INT;
						break;
					}
				}
				if (current == STATE_IN_DICT_VALUE_STR) {
					while (in >> noskipws >> ch) {
						if (ch == '"') {
							break;
						}
						value[valueLen++] = ch;
					}
				} else if (current == STATE_IN_DICT_VALUE_INT) {
					value[valueLen++] = ch;
					while (in >> noskipws >> ch) {
						if (!isdigit(ch)) {
							break;
						}
						value[valueLen++] = ch;
					}
				}
				key[keyLen] = value[valueLen] = 0;
				entry.push_back(json_field(key, value));
				if (ch == '}') {
					json->addDictionary(entry, out);
					state.pop();
				}
			} else if (ch == ',') {
				// TODO: New entry is coming.
			}
		}
	}
	return json; // TODO: Return `NULL` on failure.
}

void Json::addDictionary(json_dictionary &entry, ostream &out)
{
	static bool isFirst = true;
	if (isFirst) {
		// Builds the header.
		vector<string> header;
		for (json_dictionary::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_dictionary::iterator field = entry.begin(); field != entry.end(); ++field) {
		out << field->second << ',';
	}
	out << '\n';
}

void Json::dump(ostream &out)
{
	// Builds the header (using only the first entry).
	vector<string> header;
	for (json_dictionary::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_dictionary>::iterator entry = data.begin(); entry != data.end(); ++entry) {
		// TODO: Print fields in order (@see `header`).
		for (json_dictionary::iterator field = entry->begin(); field != entry->end(); ++field) {
			out << field->second << ',';
		}
		out << '\n';
	}
}