【ccf-csp题解】第11次csp认证-第三题-Json查询超详细讲解

此题思路来源于acwing ccfcsp认证辅导课

题目描述

 思路分析

此题的难点在于对输入的内容进行解析,题目中说除了保证字符串内容不会有空格存在之外,其它的任意地方都可能出现空格,甚至在某些地方还会出现空行,这样的话,如果一行一行地处理数据,需要做出大量的分类讨论,所以在这里使用一个技巧,就是事先把所有数据拼成一行str:

while(n--)
{
    getline(cin,s);
    str+=s;
}

拼在一起称为一个str之后,可以设置一个游标k,表示现在已经处理到的str的下标

接下来,分析对象的存储方式

我们可以写下面这样一个结构体去存储:

struct Obj
{
    int type;//1:str,2:dict
    string str;
    Obj(){}
    Obj(string _str)
    {
        type=1;
        str=_str;
    }
    map<string,Obj>obj;
}

在这里面,type为1表示字符串,为2表示字典

接下来开始对输入的对象进行解析:

首先,可以写一个解析对象的函数Obj work_obj(string,int),这个函数传入待解析对象的字符串形式和处理的起始位置(本题中实际上就是传入0就行了,当然也可以传入上面说的游标k,毕竟刚开始这个k的值一定被初始化为0)在这个函数内部,首先创建一个Obj对象obj,这个就是最终解析之后的Obj用于后续的查询,把这个obj的type设置为2。由于前面有空格存在的可能性,所以用下面的代码过滤掉’{‘,使k进入obj字典的内部:

while(str[k]!='{')k++;
k++;

 然后使用下面的代码对后续的内容进行处理,只要不见到结束的标志符号’}’就一直处理下去:

while(str[k]!='}')
{
    if(str[k]=='\"')work_kv(obj,str,k);
    else k++;
}

在这个处理的过程当中,每遇到一个双引号,就代表即将要处理一个键值对,我们再写一个函数work_kv专门处理一个键值对,参数传入对应的Obj对象,str和游标k

下面是这个work_kv函数具体实现

void work_kv(Obj& obj,string &str,int &k)
{
    auto key=work_str(str,k);
    while(str[k]!=':')k++;
    k++;
    while(str[k]!='\"'&&str[k]!='{')k++;
    if(str[k]=='\"') obj.obj[key]=Obj(work_str(str,k));
    else obj.obj[key]=work_obj(str,k);
}

首先,由于键一定是字符串,而字符串我们需要对'\'特殊处理,所以就专门地为字符串的处理写一个函数work_str,由于空格的存在,使用while循环找到':'的存在并过滤它,接下来就是对值的处理,值的开头就两种情况,如果是双引号开头就是string,如果是左大括号开头就是object。接下来对这两种情况分别讨论,如果是string,那么就直接创建一个新的OBJ对象赋给obj的字典中,如果不是string,直接调用已经写好的work_obj即可

接下来是对work_str的实现

string work_str(string &str,int &k)
{
    k++;
    string res;
    while(str[k]!='\"')
        if(str[k]=='\\')res+=str[k+1],k+=2;
        else res+=str[k++];
    k++;
    return res;
}

这个函数传入的参数和work_obj相同,第一行会首先过滤掉字符串的开头符号——双引号,然后继续遍历,如果遇到了反斜杠就跳过即可,最后返回res

以上就是解析过程的三个函数,在main函数中仅仅调用work_obj(str,0)即可,假设返回Obj类型的obj,下面是查询过程

对于每一行的查询内容,先读入整行内容,然后以’.’为依据进行分隔,放入vector<string>。由于分隔符’.’每次只会有一个,每次push_back之后,只需要让i等于j即可。对于有些以空格为依据进行分隔的情况,由于空格的数量是不确定的,所以具体要让i跳跃到哪里还需要一个新的while循环判断,当然还有一种简单的方法就是使用stringstream,链接如下:

stringstream空格分割

分成vector<string>之后,需要遍历里面的每一个string,对于每个string,需要对上述返回的obj进行迭代(就是把obj的值变成obj中的字典key为string的值),最后根据具体情况给出查询结果,具体的就看最后的代码吧

心得体会

1.学会了把多行字符串拼接成一个字符串从而避免对各种各样的空行、空格分类讨论的思想

2.学会了这种使用while循环去过滤某些字符的方法,而不是仅仅依靠string中的substr+find+replace函数去做,不仅费时间,而且代码难写

3.学会了这种使用一个全局游标+工作函数对代码的结构化简化,使得整体的思路清晰,不容易混乱

4.使用工作函数时,仅仅需要传入开始处理的位置即可,对于何时结束的问题交给工作函数本身处理就行

完整代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
struct Obj
{
    int type;  // 1: str, 2: dict
    string str;
    Obj(){}
    Obj(string _str)
    {
        type = 1;
        str = _str;
    }
    map<string, Obj> obj;
};

string work_str(string& str, int& k)
{
    k ++ ;  // 过滤掉'\"'
    string res;
    while (str[k] != '\"')
        if (str[k] == '\\') res += str[k + 1], k += 2;
        else res += str[k ++ ];
    k ++ ;  // 过滤掉'\"'
    return res;
}

Obj work_obj(string&, int&);

void work_kv(Obj& obj, string& str, int& k)
{
    auto key = work_str(str, k);
    while (str[k] != ':') k ++ ;
    k ++ ;  // 将':'过滤掉
    while (str[k] != '\"' && str[k] != '{') k ++ ;
    if (str[k] == '\"') obj.obj[key] = Obj(work_str(str, k));
    else obj.obj[key] = work_obj(str, k);
}

Obj work_obj(string& str, int& k)
{
    Obj obj;
    obj.type = 2;
    while (str[k] != '{') k ++ ;
    k ++ ;  // 过滤掉 '{'
    while (str[k] != '}')
    {
        if (str[k] == '\"') work_kv(obj, str, k);
        else k ++ ;
    }
    k ++ ;  // 过滤掉 '}'
    return obj;
}
void query(Obj o, vector<string>& qs)
{
    for (auto& s: qs)
    {
        if (o.type == 1 || !o.obj.count(s))
        {
            puts("NOTEXIST");
            return;
        }
        auto t = o.obj[s];
        o = t;
    }

    if (o.type == 1) printf("STRING %s\n", o.str.c_str());
    else puts("OBJECT");
}

int main()
{
    int n, m;
    cin >> n >> m;
    getchar();
    string str, s;
    while (n -- )
    {
        getline(cin, s);
        str += s;
    }

    int k = 0;
    auto obj = work_obj(str, k);
    while (m -- )
    {
        getline(cin, s);
        vector<string> qs;
        for (int i = 0; i < s.size(); i ++ )
        {
            int j = i + 1;
            while (j < s.size() && s[j] != '.') j ++ ;
            qs.push_back(s.substr(i, j - i));
            i = j;
        }
        query(obj, qs);
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/146174.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

由于找不到msvcp140.dll无法继续执行代码有哪些解决方法

msvcp140.dll是Microsoft Visual C 2015 Redistributable的一个组件&#xff0c;它是运行许多Windows应用程序所必需的。当msvcp140.dll丢失或损坏时&#xff0c;可能会导致以下问题&#xff1a; 1. 程序无法启动或崩溃。 2. 系统出现错误提示&#xff0c;如“找不到msvcp140…

离散卡尔曼滤波器算法详解及重要参数(Q、R、P)的讨论

公开数据集中文版详细描述参考前文&#xff1a;https://editor.csdn.net/md/?not_checkout1&spm1011.2124.3001.6192神经元Spike信号分析参考前文&#xff1a;https://blog.csdn.net/qq_43811536/article/details/134359566?spm1001.2014.3001.5501神经元运动调制分析参考…

Java学习之路 —— 异常、集合

文章目录 1. 异常2. 集合2.1 遍历2.1.1 迭代器2.1.2 增强for循环2.1.3 Lambda 2.2 List2.3 Set2.3.1 HashSet2.3.2 LinkedHashSet2.3.3 TreeSet 2.4 Map 1. 异常 Exception&#xff1a;叫异常&#xff0c;是程序员可以捕捉的。异常又分为了2类&#xff1a; 运行时异常&#x…

SpringBoot整合WebSocket实现订阅消息推送

目录 一、什么是WebSocket1.HTTP协议2.WebSocket协议 二、WebSocket使用场景1.消息推送2.实时聊天3.弹幕4.实时数据更新 三、SpringBoot整合WebSocket&#xff08;以实现消息推送为例&#xff09;1.添加依赖2.创建消息类2.WebSocket配置类3.工具类4.测试连接5.服务调用 一、什么…

人工智能 :一种现代的方法 第七章 逻辑智能体

文章目录 前言人工智能 &#xff1a;一种现代的方法 第七章 逻辑智能体7.1 基于知识的智能体7.2 Wumpus世界7.4 命题逻辑7.5 命题逻辑定理证明7.5.1推导和证明7.5.2 归结原理7.5.3 horn子句和限定子句7.5.4 前向链接和后向链接 7.6 有效命题逻辑模型求解7.6.1完备的回溯算法7.6…

MySQL主从延时问题

过线上 MySQL 维护经验的童鞋都知道&#xff0c;主从延迟往往是一个让人头疼不已的问题。 不仅仅是其造成的潜在问题比较严重&#xff0c;而且主从延迟原因的定位尤其考量 DBA 的综合能力&#xff1a;既要熟悉复制的内部原理&#xff0c;又能解读主机层面的资源使用情况&#…

使用PHP编写采集药品官方数据的程序

目录 一、引言 二、程序设计和实现 1、确定采集目标 2、使用PHP的cURL库进行数据采集 3、解析JSON数据 4、数据处理和存储 5、数据验证和清理 6、数据输出和可视化 7、数据分析和挖掘 三、注意事项 1、合法性原则 2、准确性原则 3、完整性原则 4、隐私保护原则 …

如何在 Windows 10/11 上高质量地将 WAV 转换为 MP3

WAV 几乎完全准确地存储了录音硬件所听到的内容&#xff0c;这使得它变得很大并占用了更多的存储空间。因此&#xff0c;WAV 格式在作为电子邮件附件发送、保存在便携式音频播放器上、通过蓝牙或互联网从一台设备传输到另一台设备等时可能无法正常工作。 如果您遇到 WAV 问题&…

【Android Studio调试报错】setContentView(R.layout.activity_main);

报错如下&#xff1a; 解决方法&#xff1a; 1、把参数删除到只剩 .&#xff0c;用自动补齐的方式来查看当前文件的位置是不是&#xff0c;当前左侧工程中layout 所在的位置。在的话它会在自动补齐列表有选项。否则我们选中第一个。 2、选中之后是这样的 然后问题解决&#xf…

飞天使-url路由进阶应用

url 的name属性 为 app01的url设定命名空间 app_name app01urlpatterns [path(, views.index, nameindex),path(login/, views.login, namelogin), ] 上面的namelogin 同时 from django.shortcuts import render,reverse,redirect 便于项目引用 def index(request):userna…

spring cloud-注册中心(Eureka)

一、服务注册中心组件(*) 定义&#xff1a;服务注册中心就是在整个微服务架构单独抽取一个服务&#xff0c;该服务不做项目中任何业务功能&#xff0c;仅用来在微服务中记录微服务、对微服务进行健康状态检查&#xff0c;及服务元数据信息存储常用的注册中心&#xff1a;eurek…

用placement label代替keep margin解决绕线问题

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 通常我们用keepout margin去降低多pin cell类型的密度&#xff0c;这里提供一种替代方案&#xff0c;即使用placement label。好处是只限制多pin cell彼此间距&#xff0c;不会…

echarts官网卡?

全网echarts案例资源大总结和echarts的高效使用技巧&#xff08;细节版&#xff09; - 掘金 drawnLine() {let myChart echarts.init(document.getElementById("grade"));// 绘制图表myChart.setOption({title: {left: "center",},tooltip: {trigger: &qu…

2023.11.13 Spring Bean 的生命周期

目录 Spring 执行流程 Bean 的生命周期 五个阶段 深入理解 Bean 初始化 实例理解 总结梳理 经典面试题 Spring 执行流程 Bean 的生命周期 Spring 中 Bean 的生命周就是 Bean 在 Spring 中从创建到销毁的整个过程 五个阶段 1. 实例化 Bean 为 Bean 对象分配内存空间 …

千万富翁分享:消费多少免单多少,电商运营高手实战秘籍拆解

千万富翁分享&#xff1a;消费多少免单多少&#xff0c;电商运营高手实战秘籍拆解 后疫情时代&#xff0c;国内电商圈层进程依然是在高速发展阶段&#xff0c;今年2023年双十一也彻底落下帷幕&#xff0c;但这次相较于往常却没有公布具体的成交规模数据&#xff0c;那么&#x…

程序员,你的护城河挖好了吗?

程序员的护城河 在遥远的古代&#xff0c;护城河是一种防御工事&#xff0c;通常用于保护城市或城堡免受外部攻击。它是由人工挖掘或天然形成的河流、壕沟或城墙等&#xff0c;可以作为防御屏障&#xff0c;阻止敌人的进入。 而对于程序员而言&#xff0c;“护城河”是一种比喻…

Linux线程池

文章目录&#xff1a; 线程池了解线程池模拟实现 线程池了解 线程池是一种常见的线程使用模式。线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#xff0c;等待着监督管理者分配可并发执行的任务&#xff0c;以避免在处理短时间任…

Word或者WPS批量调整文中图片大小的快捷方法

文章目录 0、前言1、编写宏代码2、在文档中调用宏实现一键批量调整3、就这么简单&#xff01; 0、前言 不知道大家是不是也和我一样&#xff0c;经常需要在编写的Word&#xff08;或者WPS&#xff09;文档里插入大量的图片&#xff0c;但是这些图片的尺寸大小一般都不一样&…

2D 3D 工业组态技术 meta2d JavaScript

本心、输入输出、结果 文章目录 2D 3D 工业组态技术 meta2d JavaScript前言2D 3D 工业组态技术 meta2d JavaScript 简介2D 3D 工业组态技术 meta2d JavaScript 特性丰富的组态能力0代码数据通信组态的应用多端适配能力强大的扩展能力追求卓越性能丰富的组件库资源广泛的应用场景…

致刘家窑中医院龚洪海医生:患者的感谢与敬意

你们好!我曾经是咱们这的一名患者&#xff0c;我叫李刚&#xff0c;今年45岁&#xff0c;不知道你们还有印象吗?我曾去过一些医院进行就诊&#xff0c;但都没有得到恰当的治疗&#xff0c;症状一直没有消失。得了这个病之后对我的生活以及工作打击都十分的大。经朋友介绍说刘家…