1. 程式人生 > >(CCF CSP 2017年9月3日) JSON查詢+詳細分析

(CCF CSP 2017年9月3日) JSON查詢+詳細分析

 JSON (JavaScript Object Notation) 是一種輕量級的資料交換格式,可以用來描述半結構化的資料。JSON 格式中的基本單元是值 (value),出於簡化的目的本題只涉及 2 種類型的值:   * 字串 (string):字串是由雙引號 " 括起來的一組字元(可以為空)。如果字串的內容中出現雙引號 ",在雙引號前面加反斜槓,也就是用 \" 表示;如果出現反斜槓 \,則用兩個反斜槓 \\ 表示。反斜槓後面不能出現 " 和 \ 以外的字元。例如:""、"hello"、"\"\\"。   * 物件 (object):物件是一組鍵值對的無序集合(可以為空)。鍵值對錶示物件的屬性,鍵是屬性名,值是屬性的內容。物件以左花括號 { 開始,右花括號 } 結束,鍵值對之間以逗號 , 分隔。一個鍵值對的鍵和值之間以冒號 : 分隔。鍵必須是字串,同一個物件所有鍵值對的鍵必須兩兩都不相同;值可以是字串,也可以是另一個物件。例如:{}、{"foo": "bar"}、{"Mon": "weekday", "Tue": "weekday", "Sun": "weekend"}。   除了字串內部的位置,其他位置都可以插入一個或多個空格使得 JSON 的呈現更加美觀,也可以在一些地方換行,不會影響所表示的資料內容。例如,上面舉例的最後一個 JSON 資料也可以寫成如下形式。   {   "Mon": "weekday",   "Tue": "weekday",   "Sun": "weekend"   }   給出一個 JSON 格式描述的資料,以及若干查詢,程式設計返回這些查詢的結果。

輸入格式

  第一行是兩個正整數 n 和 m,分別表示 JSON 資料的行數和查詢的個數。   接下來 n 行,描述一個 JSON 資料,保證輸入是一個合法的 JSON 物件。   接下來 m 行,每行描述一個查詢。給出要查詢的屬性名,要求返回對應屬性的內容。需要支援多層查詢,各層的屬性名之間用小數點 . 連線。保證查詢的格式都是合法的。

輸出格式

  對於輸入的每一個查詢,按順序輸出查詢結果,每個結果佔一行。   如果查詢結果是一個字串,則輸出 STRING <string>,其中 <string> 是字串的值,中間用一個空格分隔。   如果查詢結果是一個物件,則輸出 OBJECT,不需要輸出物件的內容。   如果查詢結果不存在,則輸出 NOTEXIST。

樣例輸入

10 5 { "firstName": "John", "lastName": "Smith", "address": { "streetAddress": "2ndStreet", "city": "NewYork", "state": "NY" }, "esc\\aped": "\"hello\"" } firstName address address.city address.postal esc\aped

樣例輸出

STRING John OBJECT STRING NewYork NOTEXIST STRING "hello"

評測用例規模與約定

  n ≤ 100,每行不超過 80 個字元。   m

 ≤ 100,每個查詢的長度不超過 80 個字元。   字串中的字元均為 ASCII 碼 33-126 的可列印字元,不會出現空格。所有字串都不是空串。   所有作為鍵的字串不會包含小數點 .。查詢時鍵的大小寫敏感。   50%的評測用例輸入的物件只有 1 層結構,80%的評測用例輸入的物件結構層數不超過 2 層。舉例來說,{"a": "b"} 是一層結構的物件,{"a": {"b": "c"}} 是二層結構的物件,以此類推。

試題分析:看到題目中字串包含著"{" ,"}",那麼我認為應該用棧的特徵,即見到“{”就入棧,遇到“}”就出棧。

題目中指出其他位置都可以插入一個或多個空格使得 JSON 的呈現更加美觀,也可以在一些地方換行,不會影響所表示的資料內容。 那麼既然這樣,乾脆用一個字串全部包含就可以了。(也就是n行的內容,用一個字串承接)

因為最後的輸出是一一對應的關係,所以利用map。

對於多種結構層數的問題,也利用棧的特性,在有“{”的情況下又來一個“{”,那麼就應該利用棧儲存住這個key(map中的key),因為往後要用到這個,在來“}”的情況,pop掉。這樣就解決了多層結構層數的問題。

再者就是字串的分析了,可以看出本題中只有一對正確的""才是起點和終點。因此需要專門的一個函式來分析字串。

#include <iostream>
#include<string>
#include<stack>
#include<map>
using namespace std;
/*
對於'{'的判斷,很明顯利用棧的性質來做.
字串是由雙引號 " 括起來的一組字元(可以為空)。
如果字串的內容中出現雙引號 ",在雙引號前面加反斜槓,也就是用 \" 表示;
如果出現反斜槓 \,則用兩個反斜槓 \\ 表示。反斜槓後面不能出現 " 和 \ 以外的字元。
*/
map<string, string>key;
map<string, string>::iterator it;
stack<string>linshi;
stack<string>qianzhui;
string c;
void change(string a, int num)//分析字串
{
	string b;
	for (int i = 0; i < a.length(); i++) {
		if (a[i] == '\\')
		{
			if (i - 1 > -1 && a[i - 1] == '\\')
			{
				a[i] = 'a';
			}
			else if (i + 1 < a.length() && a[i + 1] == '\"')
			{

			}
			else {
				b += a[i];
			}
		}
		else {
			b += a[i];
		}
	}

	if (num % 2 == 0)
	{
		key[linshi.top()] = b;
		linshi.pop();
	}
	else
	{
		if (qianzhui.size() != 0)
		{
			b = qianzhui.top() + "." + b;
		}
		linshi.push(b);
	}

}
map<string, string>ramdisk;
int main()
{
	stack<char>bigkuo;
	int n, m;
	cin >> n >> m;
	string *context = new string[n];
	string *yu = new string[m];
	string Queryfy, information;
	cin.ignore();
	for (int i = 0; i < n; i++)
	{
		getline(cin, context[i]);
		information += context[i];
	}
	for (int i = 0; i < m; i++)
		cin >> yu[i];
	int qian, hou; bool you = true; int conut = 0;//通過這個count來確認到底這個是key還是value
	for (int i = 0; i < information.length(); i++)
	{
		if (information[i] == '{') {
			bigkuo.push('{');
			if (bigkuo.size() > 1)
			{
				string u = "OBJECT0";
				qianzhui.push(linshi.top());
				change(u, conut += 1);
			}

		}
		if (information[i] == '}') {
			bigkuo.pop();
			if (bigkuo.size() > 0) {
				qianzhui.pop();

			}

		}
		if (information[i] == '"'&&information[i - 1] != '\\')//第一種字串的終止情況判斷, 例如"iosa\"dsa"
		{

			if (you) {
				qian = i;
				you = false;
			}
			else {
				hou = i; you = true;
				change(information.substr(qian + 1, hou - qian - 1), conut += 1);
			}
		}
		if (i-2>-1&&information[i] == '"'&&information[i - 1] == '\\'&&information[i-2]=='\\')//第二種字串的終止情況判斷,例如"\"\"\\\\"
		{
			hou = i;
			you = true;
			change(information.substr(qian + 1, hou - qian - 1), conut += 1);
		}
	}

	for (int i = 0; i < m; i++)
	{
		it = key.find(yu[i]);
		if (it != key.end())
		{
			if (it->second != "OBJECT0")
			{
				cout << "STRING" << " " << it->second << endl;
			}
			else {
				cout << "OBJECT" << endl;
			}
		}
		else
		{
			cout << "NOTEXIST" << endl;
		}

	}
}

明天就是CCF的考試了,不求盡如人意,但求問心無愧。