CCF 201709-3 JSON查询 90分

这个题考虑出现一些特殊情况,比如情况一:

{
    "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 <stack>
#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);
    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";

        int posKeyBegin = json.find(keyi);
        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 = "{}";   //之前提到会删除首尾大括号
        }   
    }
    return value;
}

int main()
{
    int n,m;
    string json ="";
    //freopen("t2.txt", "r", stdin);
    cin >> n >>m;
    cin.get();
    for(int i=0; i<n; i++) 
    {
        string s;
        getline(cin, s);
        json += s;
    }


    //cout<<json<<endl;
    map<string, string> repString; //替换空白符和引号等,注意反斜杠的转义
    repString["\n"] = "", repString[" "] = "", repString["\t"] = ":";
    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);

    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;
}

猜你喜欢

转载自blog.csdn.net/gengli2017/article/details/82148754
今日推荐