这个题考虑出现一些特殊情况,比如情况一:
{
"a":"11",
"b": { "first" : "1", "second" : "2"}
}
直接查 first, 应该查不到才对。代码中考虑了情况一。
还有一种情况,不知测试数据中有没有,应该不会有吧,代码中没有考虑,因为比较复杂。
情况二:
{
"a" : "1",
"b" : { "a" : "23"}
}
感觉这种嵌套不用考虑。为什么90分我也不知道,自己3级数据试试也能查。
思路:
1. 去掉多余空白符,把json数据变成一个字符串
2. 去掉转义的反斜杠和包住键、值的双引号,但键或值本身的双引号不能去
3. 把查询的字符串,例如 address.city 等从 “.” 处拆开,依次放入向量(vector)
4. 依次取出向量元素,例如: 假设向量是 [a, b, c],先以 a 为键查找,若找到,则截取 a 的键值(原字符串的子字符串), 在子字符串中以 b 为键值继续查找。
5. 考虑上面情形一,通过大括号的数量和键的深度十分匹配来判断。(不考虑辞典可以得 80 分)
代码如下:
#include <vector>
#include <map>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
//字符串替换函数,直接在网上找到改编的,看起来不错
string& replace_all_distinct(string& str, const string& old_value, const string& new_value)
{
for(string::size_type pos(0); pos != string::npos; pos += new_value.length())
{
if((pos = str.find(old_value, pos)) != string::npos)
str.replace(pos, old_value.length(), new_value);
else break;
}
return str;
}
//把查询分割成向量
vector<string> key2Vector(string &key)
{
key += ".";
vector<string> vs;
while(key != "")
{
int pos = key.find(".");
string sub = key.substr(0, pos);
vs.push_back(sub);
key.erase(0, pos+1);
}
return vs;
}
//用左右大括号数量来判断键的深度, 看是否与deep相等,deep是查询的实际深度
bool keyiIsInFirstLayer(string json, string keyi, int deep)
{
int posKeyi = json.find(keyi);
if(posKeyi > 0)
while(isalpha(json[posKeyi - 1]) && posKeyi != string::npos) //while循环处理情况三
posKeyi = json.find(keyi, posKeyi + 1);
int nowdeep= -1;
for(int i=0; i< posKeyi; i++)
{
if(json[i] == '{') ++nowdeep;
else if(json[i] == '}') --nowdeep;
}
return deep == nowdeep;
}
//主要函数,输入原始json和一个键向量,返回一个查询的结果
string findValue(string json, vector<string> key)
{
string value;
string rawjson = json;
for(int i=0; i<key.size(); i++) //依次处理键
{
json.erase(0,1);
json.erase(json.length()-1, 1); //去掉首位大括号,可以带来一些简便
string keyi = key[i];
keyi += ":";
if( ! keyiIsInFirstLayer(rawjson, keyi, i)) //判断深度是否一致
return "NOTEXIST";
//cout << "he"<<endl;
int posKeyBegin = json.find(keyi);
if(posKeyBegin > 0)
while(isalpha(json[posKeyBegin - 1]) && posKeyBegin != string::npos)
posKeyBegin = json.find_first_of(keyi, posKeyBegin + 1);//处理情况三
int posKeyEnd = posKeyBegin + keyi.length(); //本结构用的都是左闭右开区间
//即字符串实际部分是[posKeyBegin, posKeyEnd), 希望能理解
if(posKeyBegin == string::npos)
return "NOTEXIST";
if(json[posKeyEnd] == '{') //如果是大括号
{
value = "OBJECT"; //先定为object,如果还有键,会被更新
int posValueBegin = posKeyEnd;
int count=1;
int posValueEnd;
for(posValueEnd=posKeyEnd + 1; count !=0; posValueEnd++)
{
if(json[posValueEnd] == '{') ++count;
if(json[posValueEnd] == '}') --count;
}
json = json.substr(posValueBegin, posValueEnd-posValueBegin);
//此时的json为: {应该有的东西}, 注意此时首尾有大括号
}
else //是字符串
{
int posValueBegin = posKeyEnd;
int posValueEnd = json.find_first_of(",", posValueBegin) ;
if(posValueEnd != string::npos)
value = json.substr(posValueBegin, posValueEnd - posValueBegin);
else
value = json.substr(posValueBegin);
value = "STRING " + value;
json = "{}"; //之前提到会删除首尾大括号
}
//cout << json << endl;
}
return value;
}
int main()
{
int n,m;
string json ="";
//freopen("json.txt", "r", stdin);
cin >> n >>m;
cin.get();
for(int i=0; i<n; i++)
{
string s;
getline(cin, s);
json += s;
}
map<string, string> repString; //替换空白符和引号等,注意反斜杠的转义
repString["\n"] = "", repString[" "] = "", repString["\t"] = "";
repString["\":\""] = ":", repString["\",\""]=",";
repString["{\""] = "{", repString["\"}"] = "}";
repString["\":{\""] = ":{", repString["},\""] = "}," ;
repString["\\\\"] = "\\", repString["\\\""] = "\"";
for(map<string, string>::iterator it= repString.begin(); it != repString.end(); it++)
replace_all_distinct(json, it->first, it->second);
//cout<<json<<endl;
for(int i=0; i<m; i++) //一条一条数据处理
{
string key;
cin >> key;
vector<string> kv = key2Vector(key);
string value = findValue(json, kv);
cout << value <<endl;
}
return 0;
}