ccf 201709-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 ,其中 是字符串的值,中间用一个空格分隔。
  如果查询结果是一个对象,则输出 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”}} 是二层结构的对象,以此类推。

这道题我做的时候只有80分,后来参照网上大神代码,终于找到扣20分的位置,拿到100分,我会在后面c++版代码那里做出示意。。。。在此贴上大神网址,感谢 L_Aster 大神分享,他的代码更加简洁,效率也更高:http://blog.csdn.net/gl486546/article/details/78277172

思路:将多个“.”分割开,然后用字符串查找的方法,找 “{” 和“}”。。。。不过,这个方法好像有个弊端,就是如果在键中,有“{”或者“}”的话,会失效,比如:

13 1
{
"firstName": "OBJECT",
"address11": {
"s}": "21",
"city11": "h1"
},
"address1": {
"s}": "2",
"city1": "h"
"ss":{"a":"b"}
},
"esc\\aped": "\"hello\""
}
address11.city11
返回是:NOTEXIST

不过,好像ccf中没有这样的例子,所以也100分了。。。同样的方法,对比一下java和c++……

json查询

C++版

/*
 这道题的坑位。。。。查找键的时候,要带上后面的‘:’,要不然前50分只能拿20分
 */
#include <iostream>
#include <vector>
#include<algorithm>
using namespace std;
bool isroot(string &jsonstr,size_t pos)
{
    //这里也是从L_Aster大神那里学到的,如果不加,扣10分
    //可以用来检测是不是key。。。。
    int pcnt=0;
    for(size_t i=0;i<pos;++i)
    {
        if(jsonstr[i]=='{') ++pcnt;
        if(jsonstr[i]=='}') --pcnt;
    }
    return pcnt==0;
}

void clean_str(string *str){
    // 这里是我自己写的函数,无法很好的处理有连续好多个‘/’的情况
    string *s = str;
    string::size_type s_t;
    // 这里除去空格和多余的’”‘
    string t = " ";
    while((s_t=s->find(t, 0)) != string::npos){
        s->erase(s_t,t.length());
    }
    // 这里处理 多余的 ’“‘
    string::size_type start_index;
    t = "\\";
    start_index = 0;
    while((s_t=s->find(t, start_index)) != string::npos){
        if(*(s->begin()+s_t+1) == '\\'){
            s->erase(s_t+1,t.length());
            start_index = s_t-1;
            continue;
        }
        start_index ++;
    }
    // 这里处理 ‘\"’
    t = "\\";
    start_index = 0;
    while((s_t=s->find(t, start_index)) != string::npos){
        if(*(s->begin()+s_t+1) == '"'){
            s->erase(s_t,t.length());
            start_index = s_t;
            continue;
        }
        start_index ++;

    }
}

string find_object(string str, string d_obj)
{

//    cout<<str<<"***"<<d_obj<<endl;
    size_t str_s=str.find(d_obj, 0), s1;
    if(str_s == string::npos) return "NOTEXIST";
    int count_l=0, count_l_r=0;
    string result;
    int i;
    for (i = str_s+d_obj.size()-1; i < str.length(); ++i) {
        if(str[i]=='{') count_l++;
        if(str[i]=='}') count_l_r++;
        if(count_l_r == count_l && count_l!=0) break;
    }
    if(count_l_r!=count_l) return "NOTEXIST";
    s1=str.find(d_obj, 0);
    s1 = str.find(":{", s1);
    result = str.substr(s1, i-s1+1);
    result.erase(0,1);
    result.erase(0,1);
    result.erase(result.length()-1, 1);
//    cout<<"result is:"<<result<<endl;
    return result+",";
}
string detect_str_result(string str_v, string str){
    size_t index_s=0, index_e;
    string result;
    string exam_s = str_v+"\":";
    index_s = str.find(exam_s, index_s);
    if(index_s == string::npos || !isroot(str,index_s)) return "NOTEXIST";  //这个位置使用isroot函数
    else{
        if(str[index_s+exam_s.length()]=='{') return "OBJECT";
        else{
            index_e = str.find("\",", index_s);
            result = str.substr(index_s+exam_s.length(), index_e-exam_s.length()-index_s+1);
            return result;
        }
    }
    // 这里是50分
}

string detect_str(vector<string> &str_v, string str){
    //如果有多层,则,反复提取出其中的object,然后传入只有一层的函数中
    for(int i=0;i<str_v.size()-1;i++){
        str = find_object(str, "\""+str_v[i]+"\":{");
        if(str.compare("NOTEXIST")==0) return "NOTEXIST";
    }
    return detect_str_result(str_v.back(), str);
}

void find_key(vector<string>&str_v, string exam_str){
    size_t index_s = 0, index_e;

    while((index_e = exam_str.find(".", index_s))!=string::npos){
        string key = exam_str.substr(index_s, index_e-index_s);
        str_v.push_back(key);
        index_s = index_e+1;
    }

    exam_str = exam_str.substr(index_s, exam_str.find("\n", index_s)-index_s);
    str_v.push_back(exam_str);
}
int main(){
    int n, m;
    string s;
    vector<string> strs_v;
    string str_all="", exam_str, key;

    /*
     这里是我扣10分的地方,如果用clearn_str函数,不但代码更加长,
     而且,不能很好的处理类似于"//firstname"这样的键
     换成后面的代码,就很好了
    cin>>n>>m;
    cin.get();
    while(n--){
        getline(cin, exam_str);
        str_all += exam_str;
    }
    clean_str(&str_all);
    str_all.erase(0,1);
    str_all[str_all.length()-1] =  ',';
     */

    cin>>n>>m;
    cin.get();
    cin.get();
    for(int i=0;i<n;++i)
    {
        char ch;
        while((ch=cin.get())!='\n')
        {
            if(ch==' ') continue;  //去掉空格
            if(ch=='\\')
            {
                str_all+=cin.get();  //去掉‘\’,无论后面是啥,前面那个’\‘总是没用的
                continue;
            }
            str_all+=ch;
        }
    }
    str_all[str_all.length()-1] =  ',';
//    cout<<str_all<<endl;

    while(m--){
        cin>>exam_str;
        find_key(strs_v, exam_str);
        if(strs_v.size()==1)
        {
            //一层
            string exam = detect_str_result(strs_v[0], str_all);
            if(exam.compare("OBJECT")==0) cout<<"OBJECT"<<endl;
            else if(exam.compare("NOTEXIST") == 0) cout<<"NOTEXIST"<<endl;
            else {
                exam.erase(0,1);
                exam.erase(exam.length()-1,1);
                cout<<"STRING "<<exam<<endl;
            }
        }
        else{
            //多层
            string exam = detect_str(strs_v, str_all);
            if(exam.compare("OBJECT")==0) cout<<"OBJECT"<<endl;
            else if(exam.compare("NOTEXIST") == 0) cout<<"NOTEXIST"<<endl;
            else {
                exam.erase(0,1);
                exam.erase(exam.length()-1,1);
                cout<<"STRING "<<exam<<endl;
            }

        }
        strs_v.clear();
    }
    return 0;
}

Java

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main {

    public static boolean isroot(String jsonstr, Integer pos){
        Integer pcnt=0;
        for(Integer i=0;i<pos;++i){
            if(jsonstr.charAt(i) == '{') ++pcnt;
            if(jsonstr.charAt(i) == '}') --pcnt;
        }
        return pcnt == 0;
    }

    public static ArrayList<String> find_key( String exam_str){
        String x[] = exam_str.split("\\.");  //  \\是转义符
        ArrayList<String> str_v = new ArrayList<String>(Arrays.asList(x));
        return str_v;
    }

    public static String find_object(String str, String d_obj){
        Integer str_s = str.indexOf(d_obj, 0), s1;
        if(str_s == -1 || !isroot(str, str_s)) {
            return "NOTEXIST";
        }
        int count_l = 0, count_l_r=0;
        String result;
        int i;
        for(i=str_s+d_obj.length()-1; i<str.length(); ++i){
            if(str.charAt(i) == '{') count_l++;
            if(str.charAt(i) == '}') count_l_r++;
            if(count_l == count_l_r && count_l!=0) {
                break;
            }
        }
        if(count_l != count_l_r) {
            return "NOTEXIST";
        }
        s1 = str.indexOf(d_obj, 0);
        s1 = str.indexOf(":{", s1);
        result = str.substring(s1+2, i);
        return result+",";
    }

    public static String detect_str(ArrayList<String> str_v, String str){
        for (int i=0; i<str_v.size()-1; i++){
            str = find_object(str, "\""+str_v.get(i)+"\":{");
            if(str.compareTo("NOTEXIST")==0) {
                return "NOTEXIST";
            }
        }
        return detect_str_result(str_v.get(str_v.size()-1), str);
    }

    public static String detect_str_result(String str_v, String str){
        Integer index_s = 0, index_e;
        String result;
        String exam_s = "\""+str_v+"\":";
        index_s = str.indexOf(exam_s, index_s);
        if(index_s==-1 || !isroot(str, index_s)) return "NOTEXIST";
        else{
            if(str.charAt(index_s+exam_s.length())=='{') return "OBJECT";
            else{
                index_e = str.indexOf("\",", index_s);
                result = str.substring(index_s+exam_s.length(), index_e+1); //这里java和c++不同,第二个参数是截至位置的下标
                return result;
            }
        }
    }

    public static void main(String[] args) {
        int n, m;
        String s;
        ArrayList<String> strs_v = new ArrayList<String>();
        Scanner ss = new Scanner(System.in);
        String str_all = "", exam_str, key;
        n = ss.nextInt();
        m = ss.nextInt();
        for(int i=0;i<=n;i++){
            s = ss.nextLine();
            for (int j=0;j<s.length();j++){
                char ch = s.charAt(j);
                if(ch == ' ') continue;
                if(ch == '\\'){
                    str_all += s.charAt(++j);
                    continue;
                }
                str_all += ch;
            }
        }
        str_all = str_all.substring(1);
        str_all = str_all.substring(0,str_all.length()-1);
        str_all += ",";
        while(m-->0){
            exam_str = ss.next();
            strs_v = find_key(exam_str);
            if (strs_v.size() == 1){
                // 一层
                String exam = detect_str_result(strs_v.get(0), str_all);
                if(exam.compareTo("OBJECT")==0) System.out.println("OBJECT");
                else if(exam.compareTo("NOTEXIST")==0) System.out.println("NOTEXIST");
                else{
                    exam = exam.substring(1, exam.length());
                    exam = exam.substring(0, exam.length()-1);
                    System.out.println("STRING "+exam);
                }
            }
            else{
                String exam = detect_str(strs_v, str_all);
                if(exam.compareTo("OBJECT")==0){
                    System.out.println("OBJECT");
                }
                else if(exam.compareTo("NOTEXIST")==0){
                    System.out.println("NOTEXIST");
                }
                else{

                    exam = exam.substring(1, exam.length());
                    exam = exam.substring(0, exam.length()-1);
                    System.out.println("STRING "+exam);
                }
            }
            strs_v.clear();
        }
    }
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值