问题描述
实现技巧
这种需要嵌套定义并且类型不一时,可以用变量区分变量类型
结构体里不能嵌套unordered_map,可以嵌套map
对于多个函数操作一个字符串,可以将指针加引用,相当于指针跟着函数的操作移动,不需要再额外增加形参记录当前指针位置
反斜杠需要用//
使用未定义函数需要申明,不需要变量名
在选择结构中,如果该部分代码太长,也拎出来写,这样使得选择结构清晰易读,逻辑清晰
会多次用到的部分,使用函数来表示
不能直接赋值,会出错(该结构体的嵌套结构体赋给该结构体时。。maybe)
erase删除后,字符会左移,原来的下一个字符会变成当前这个字符,处理的时候要考虑到这个问题
答案特判输出时,询问情况应考虑全面
解题思路
- 采用 map < string, node >进行存储,node是结构体,可以是string,也可以是嵌套的map < string, node >
- 首先先将内容存储下来,全部存成一行,先提出所有多余的空格
- 从{后的第一个字符开始递归处理对象
- 处理键值对,若值为对象,递归处理
- 将查询根据.进行分隔,用queue进行存储,如果不是最后一项,则更新查询的对象,如果是最后一项,则输出答案
- 代码1和代码2解题思路差不太多,代码2多用函数封装,更简洁
代码实现1 :条例清晰版本
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
struct node
{
bool is_obj; //这个节点是否是对象
string val; //字符串的值
map <string, node> obj; //对象
};
map <string, node> res; //只能用map,不能用unordered_map
void workBlank(string &str) //去除多余的空格
{
string t;
for (int i = 0; i < str.size(); i ++)
{
if (str[i] != ' ') t += str[i]; //只要不是空格的字符就要
}
str = t;
}
map <string, node> Object(string str, int &i)
{
map <string, node> obj;
if (str[i] == '}') //如果是空对象
{
i ++;
return obj;
}
for (; i < str.size();)
{
if (str[i] == '"') //这一定是键值对的key的第一个引号
{
//处理key
int j = i + 1; //指向"后一位
string key;
while (j < str.size() && str[j] != '"') //结束是j等于"
{
if (str[j] != '\\') key += str[j];
else key += str[ ++ j]; //加上\后面那位
j ++;
}
//处理value
i = j + 2; //i指向冒号后面一位
if (str[i] == '"') //值为string
{
int j = i + 1; //“后的第一个字符
string value;
while (j < str.size() && str[j] != '"') //结束是j等于"
{
if (str[j] != '\\') value += str[j];
else value += str[ ++ j]; //加上\后面那位
j ++;
}
obj[key].is_obj = false;
obj[key].val = value;
i = j + 1; //i指向"后一位,可能是,或者}
}
else //值为对象
{
i ++; //i指向{后一位进入递归
obj[key].is_obj = true;
obj[key].obj = Object(str, i); //返回时j指向}后一位,可能是,或者}
}
if (str[i] == ',')
{
i ++; //i指向"
continue;
}
else //只有可能是}
{
i ++; //返回时j指向}后一位,可能是,或者}
//cout << str[i];
return obj;
}
}
}
}
queue <string> pushin(string str)
{
queue <string> res;
for (int i = 0; i < str.size();)
{
int k = str.find('.', i);
if (k == -1) //后面没有.
{
res.push(str.substr(i));
break;
}
else
{
res.push(str.substr(i, k - i));
i = k + 1; //i指向.后一位
continue;
}
}
return res;
}
int main()
{
int n, m;
cin >> n >> m;
string str;
getchar();
while (n --)
{
string t;
getline(cin, t);
str += t; //将所有内容拼接成一行
}
workBlank(str); //去除多余的空格
//cout << str;
int pos = 1;
res = Object(str, pos); //递归处理对象,从{下一位开始
//查询
while (m --)
{
cin >> str;
queue <string> q = pushin(str); //根据.进行分隔询问
map <string, node> tmp1 = res;
while (q.size())
{
string key = q.front();
if (tmp1.count(key) == 0)
{
//for (auto x : tmp1) cout << x.first << endl;
puts("NOTEXIST");
break;
}
if (q.size() == 1) //查询的最后一项
{
if (tmp1[key].is_obj) puts("OBJECT");
else cout << "STRING" << " " << tmp1[key].val << endl;
}
else //更新查询的对象
{
if (tmp1[key].is_obj == false) //如果该value不是对象,说明查询失败,因为这项不是最后一项,一定是对象
{
puts("NOTEXIST");
break;
}
else
{
map <string, node> tmp2 = tmp1[key].obj;
tmp1 = tmp2;
}
}
q.pop();
}
}
return 0;
}
代码实现2 :最短代码版本
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
//这种需要嵌套定义并且类型不一时,可以用变量记录变量类型
struct Obj
{
int type; //1为str, 2为obj
string str;
Obj(){}
Obj(string t)
{
type = 1;
str = t;
}
//结构体里不能嵌套unordered_map,可以嵌套map
map <string, Obj> kv; //对象中的key-value对
};
//会多次用到的部分,使用函数来表示
string work_str(string &str, int &pos)
{
pos ++; //滤过'"'
string s;
while (pos < str.size() && str[pos] != '\"')
{
if (str[pos] == '\\') s += str[pos + 1], pos += 2; //反斜杠需要用//
else s += str[pos ++];
}
pos ++; //滤过'"'
return s;
}
//使用前需要申明,不需要变量名
Obj work_obj(string &, int &);
//在选择结构中,如果该部分代码太长,也拎出来写,这样使得选择结构清晰易读,逻辑清晰
void work_kv(Obj &thisobj, string &str, int &pos)
{
string key = work_str(str, pos);
pos = str.find(':', pos); //找到':'位置
while (str[pos] != '\"' && str[pos] != '{') pos ++;
if (str[pos] == '\"') thisobj.kv[key] = Obj(work_str(str, pos));
else thisobj.kv[key] = work_obj(str, pos);
}
Obj work_obj(string &str, int &pos)
{
Obj thisobj;
thisobj.type = 2;
while (pos < str.size() && str[pos] != '{') pos ++;
pos ++; //过滤掉'{'
while (pos < str.size() && str[pos] != '}')
{
if (str[pos] == '\"') work_kv(thisobj, str, pos);
else pos ++;
}
pos ++; //滤过'}'
return thisobj;
}
void query(Obj obj, vector <string> qs)
{
for (auto q : qs)
{
if (obj.type == 1 || obj.kv.count(q) == 0)
{
puts("NOTEXIST");
return ;
}
// 不能直接赋值,会出错(该结构体的嵌套结构体赋给该结构体时。。maybe)
Obj t = obj.kv[q];
obj = t;
}
if (obj.type == 1) printf("STRING %s\n", obj.str.c_str());
else puts("OBJECT");
}
int main()
{
int n, m;
cin >> n >> m;
getchar();
string str, tmp;
while (n --)
{
getline(cin, tmp);
str += tmp; //将整个对象合并成一个串
}
int p = 0; //串的起始位置
auto mainobj = work_obj(str, p); //处理最外层的对象
while (m --)
{
getline(cin, tmp);
vector <string> qs; //存储每一个查询
for (int i = 0; i < tmp.size(); i ++)
{
int j = i + 1;
while (j < tmp.size() && tmp[j] != '.') j ++;
qs.push_back(tmp.substr(i, j - i));
i = j;
}
query(mainobj, qs);
}
return 0;
}