Cod sursa(job #1358538)

Utilizator MrWhiteDELETEME MrWhite Data 24 februarie 2015 17:51:33
Problema Convertor Scor 80
Compilator cpp Status done
Runda rosedu_cdl_2015 Marime 5.56 kb
/**
 * Converts JSON to CSV.
 */

#include <algorithm>
#include <fstream>
#include <iostream>
#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 dictionary value (expects string). */
		STATE_IN_DICT_VALUE_STR,

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

		/** Final state. */
		STATE_END,
	};
};

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

Json* JsonParser::parse(istream &in, ostream &out)
{
	Json *json = new Json;
	json_dictionary dict;
	char ch, key[128], value[1024];
	int keyLen = 0, valueLen = 0;
	State state = STATE_NONE;
	while (state != STATE_END) {
		in >> ch;
		if (state == STATE_NONE) {
			if (ch == '[') {
				// Array found.
				state = STATE_IN_ARRAY;
			} 
		} else if (state == STATE_IN_ARRAY) {
			if (ch == ']') {
				// Array ended.
				state = STATE_END;
			} else if (ch == '{') {
				// Dictionary found. Resetting everything.
				dict.clear();
				state = STATE_IN_DICT;
			}
		} else if (state == STATE_IN_DICT) {
			if (ch == '"') {
				// Key found. Resetting everything.
				keyLen = valueLen = 0;
				// Reading key.
				while (in >> noskipws >> key[keyLen]) {
					if (key[keyLen] == '"') {
						break;
					}
					++keyLen;
				}
				// Finding the delimiter between key and value.
				while (in >> ch) {
					if (ch == ':') {
						break;
					}
				}
				// Determining value type.
				while (in >> ch) {
					if (ch == '"') {
						state = STATE_IN_DICT_VALUE_STR;
						break;
					} else if (isdigit(ch)) {
						state = STATE_IN_DICT_VALUE_INT;
						break;
					}
				}
				// Reading value.
				if (state == STATE_IN_DICT_VALUE_STR) {
					while (in >> noskipws >> value[valueLen]) {
						if (value[valueLen] == '"') {
							break;
						}
						++valueLen;
					}
				} else if (state == STATE_IN_DICT_VALUE_INT) {
					value[valueLen++] = ch;
					while (in >> value[valueLen]) {
						if (!isdigit(value[valueLen])) {
							break;
						}
						++valueLen;
					}
				}
				// Pushing the field.
				key[keyLen] = value[valueLen] = 0;
				dict.push_back(json_field(key, value));
				// Pushing the dictionary aswell if it ended now.
				if (ch == '}') {
					json->addDictionary(dict, out);
					state = STATE_IN_ARRAY;
				} else {
					state = STATE_IN_DICT;
				}
			} else if (ch == '}') {
				// Dictionary ended.
				json->addDictionary(dict, out);
				state = STATE_IN_ARRAY;
			}
		}
	}
	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';
	}
}