【CSP试题回顾】201709-3-JSON查询

news2024/9/28 7:24:54

CSP-201709-3-JSON查询

解题思路

1. 初始化数据结构

  • map<string, string> strContent: 存储字符串类型属性的内容。键是属性名(可能包含通过点.连接的多级属性名),值是属性的字符串值。
  • vector<string> keyVec: 存储当前正在处理的属性路径。例如,对于嵌套的对象,这个向量帮助跟踪当前的属性名路径。
  • set<string> objContent: 存储对象类型属性的集合,只保存对象属性的键名。

2. 解析JSON字符串

  • ProcessObject函数用于处理JSON对象,它逐字符读取JSON字符串,识别出键和值,并根据值的类型(字符串或对象)进行相应的处理。
  • 当发现一个双引号"时,会调用GetStr函数提取双引号之间的字符串,处理转义字符,并返回字符串值。这个返回的字符串可能是键也可能是值,取决于它的上下文位置。
  • 当发现一个冒号:时,表明接下来的部分是值,此时会调用ProcessPropertyContent来处理这个值。

3. 处理属性内容

  • ProcessPropertyContent函数用来处理和存储属性的内容。这个函数会根据值的类型来决定下一步的操作:
    • 如果值是字符串(以双引号开头),则将该字符串与当前的属性路径(由keyVec构建)关联,并存储到strContent映射中。
    • 如果值是对象(以左花括号{开头),则记录这个属性是对象类型(存储到objContent),并递归调用ProcessObject来处理这个嵌套对象。

4. 查询处理

  • 主函数最后部分读取查询,并根据查询的键去查找之前解析的JSON数据:
    • 如果查询的键对应的是字符串类型的属性,则从strContent中获取该属性的值,并以STRING <value>的格式输出。
    • 如果查询的键对应的是对象类型的属性,则检查objContent集合,如果存在,则输出OBJECT
    • 如果查询的键在JSON中不存在,则输出NOTEXIST

总结解题思路

  1. 初始化和解析: 代码首先初始化用于存储数据的结构,然后逐行读取输入的JSON数据,将其拼接成一个完整的字符串。

  2. 处理JSON对象: 使用ProcessObject函数逐个字符遍历整个JSON字符串,利用GetStr函数提取出键和字符串值,并根据上下文确定它们是键还是值。对于每个键值对,如果值是字符串,就将它存储在strContent映射中;如果值是另一个对象,则将键存储在objContent集合中,并递归地处理这个嵌套对象。

  3. 构建属性路径: 在解析过程中,使用keyVec向量跟踪当前的属性路径(例如,对于嵌套的对象)。这个属性路径用于构建strContent映射和objContent集合中的键。

  4. 回答查询: 最后,对于每个查询,程序检查该属性是否存在于strContentobjContent中,并按照格式要求输出结果。

【100分代码】

#include <iostream> 
#include <string>   
#include <map>    
#include <vector>  
#include <set>      
#include <algorithm> 
using namespace std;

map<string, string> strContent; // 存储字符串类型属性内容的映射
vector<string> keyVec; // 存储当前处理路径的键向量
set<string> objContent; // 存储对象类型属性内容的集合

void ProcessPropertyContent(int& i, string& jsonStr); // 函数声明,因为ProcessObject中要调用ProcessPropertyContent

string GetStr(int& i, string& jsonStr) { // 提取双引号之间的字符串,此字符串可能是键,也可能是值
    string result = "";
    while (++i) {
        if (jsonStr[i] == '\\') { // 处理转义字符
            result += jsonStr[++i];
        }
        else if (jsonStr[i] == '"') { // 遇到闭合引号则停止
            break;
        }
        else {
            result += jsonStr[i];
        }
    }
    return result;
}

// 处理JSON对象,从start到end之间的字符串
void ProcessObject(int start, int end, string& jsonStr) {
    for (int i = start + 1; i < end; ++i) {
        if (jsonStr[i] == '"') { // 遇到引号,后面的内容是键
            keyVec.push_back(GetStr(i, jsonStr));
        }
        else if (jsonStr[i] == ':') { // 遇到冒号,后面的内容是值
            ProcessPropertyContent(i, jsonStr);
        }
    }
    if (!keyVec.empty()) {
        keyVec.pop_back(); // 移除处理完的键
    }
}

// 处理属性内容,可以是字符串或对象
void ProcessPropertyContent(int& i, string& jsonStr) {
    // 初始化fullKey,开始构建完整的键名
    string fullKey;
    if (!keyVec.empty()) {
        fullKey = keyVec[0]; // 开始时fullKey为第一个键名
        for (int j = 1; j < keyVec.size(); ++j) { // 遍历剩余的键名
            fullKey += "." + keyVec[j]; // 将键名用点连接起来
        }
    }

    // 解析jsonStr中的属性值
    while (++i) {
        if (jsonStr[i] == '"') { // 如果属性值是字符串
            keyVec.pop_back(); // 从路径中移除当前键
            strContent[fullKey] = GetStr(i, jsonStr); // 存储键值对
            return;
        }
        else if (jsonStr[i] == '{') { // 如果属性值是对象
            objContent.insert(fullKey); // 记录这是一个对象
            int count = 1; // 用于匹配花括号
            int j = i; // 记录当前位置
            while (count) { // 查找匹配的闭合花括号
                j++;
                if (jsonStr[j] == '{') count++;
                else if (jsonStr[j] == '}') count--;
            }
            ProcessObject(i, j, jsonStr); // 递归处理嵌套对象
            i = j; // 跳过已处理的对象
            return;
        }
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    getchar(); // 消耗换行符
    string temp, jsonStr = "";
    for (int i = 0; i < n; ++i) {
        getline(cin, temp);
        jsonStr += temp;
    }
    ProcessObject(0, jsonStr.size(), jsonStr); // 处理整个JSON字符串
    for (int i = 0; i < m; ++i) {
        cin >> temp;
        if (strContent.count(temp)) // 查询字符串类型的属性
            cout << "STRING " << strContent[temp] << endl;
        else if (objContent.count(temp)) // 查询对象类型的属性
            cout << "OBJECT" << endl;
        else // 属性不存在
            cout << "NOTEXIST" << endl;
    }
}

请添加图片描述

【70分代码:未处理二级对象结构】

#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <string>
#include <algorithm> /
using namespace std;

struct MyObject {
    string objName;
    map<string, string> strMap;
};

vector<MyObject> objList;
map<string, string> globalStringMap; // 全局字符串map,避免重复定义

void init(string& t) { // 初始化函数,处理转义字符
    size_t pos = 0;
    while ((pos = t.find("\\\"", pos)) != string::npos) { // 处理转义双引号
        t.erase(pos, 1);
    }
    pos = 0; // 处理转义反斜杠
    while ((pos = t.find("\\\\", pos)) != string::npos) {
        t.erase(pos, 1);
    }
}


void parseJSON(string& text) { // 解析JSON字符串,填充对象列表和全局字符串map
    // 预处理输入文本:移除空格和最外层的大括号
    text.erase(remove(text.begin(), text.end(), ' '), text.end());
    text = text.substr(1, text.length() - 2);

    stringstream ss(text);
    string token;
    bool inString = false;
    while (getline(ss, token, ',')) {
        // 处理字符串外的逗号分割
        if (!inString) {
            // 检查是否为对象起始
            if (token.find('{') != string::npos) {
                // 对象处理逻辑
                string objName = token.substr(1, token.find(':') - 2);
                init(objName);
                // 获取对象内容
                size_t pos = token.find('{');
                string objContent = token.substr(pos + 1);
                objContent.pop_back(); // 移除末尾的}

                MyObject newObj;
                newObj.objName = objName;

                stringstream objStream(objContent);
                string pair;
                while (getline(objStream, pair, ',')) {
                    size_t sepPos = pair.find(':');
                    string key = pair.substr(1, sepPos - 2);
                    string value = pair.substr(sepPos + 2, pair.length() - sepPos - 3);
                    init(key);
                    init(value);
                    newObj.strMap[key] = value;
                }
                objList.push_back(newObj);
            }
            else {
                // 全局字符串处理逻辑
                size_t sepPos = token.find(':');
                string key = token.substr(1, sepPos - 2);
                string value = token.substr(sepPos + 2, token.length() - sepPos - 3);
                init(key);
                init(value);
                globalStringMap[key] = value;
            }
        }
    }
}

// 查询逻辑
void query(const string& q) {
    if (q.find('.') == string::npos) { // 查询全局字符串或对象名
        if (globalStringMap.count(q)) {
            cout << "STRING " << globalStringMap[q] << endl;
        }
        else {
            bool found = false;
            for (auto& obj : objList) {
                if (obj.objName == q) {
                    cout << "OBJECT\n";
                    found = true;
                    break;
                }
            }
            if (!found) cout << "NOTEXIST\n";
        }
    }
    else { // 查询对象内的字符串
        auto dotPos = q.find('.');
        string objName = q.substr(0, dotPos);
        string key = q.substr(dotPos + 1);

        for (auto& obj : objList) {
            if (obj.objName == objName) {
                if (globalStringMap.count(key)) {
                    cout << "STRING " << globalStringMap[key] << endl;
                    return;
                }
            }
        }
        cout << "NOTEXIST\n";
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    getchar(); // 消耗掉换行符

    string text, line;
    for (int i = 0; i < n; ++i) {
        getline(cin, line);
        text += line;
    }

    // 解析JSON字符串
    parseJSON(text);

    // 查询
    for (int i = 0; i < m; ++i) {
        string q;
        cin >> q;
        query(q);
    }

    return 0;
}

请添加图片描述


文章部分内容参考自:CSP201709-3JSON查询

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

酒店客房管理系统设计与实现(论文+源码)_kaic

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本酒店客房管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息…

SpringBoot+vue3打造企业级一体化SaaS系统

SpringBootvue3打造企业级一体化SaaS系统 简介&#xff1a;    全面提升前后端技术水平&#xff0c;独立完成全栈项目开发能力&#xff0c;快速进击全栈工程师&#xff0c;最终在面试中脱颖而出。整合后端主流技术&#xff08;Spring Boot、物理数据库隔离、加载动态权限、多…

网络基础 - 预备知识(协议、网络协议、网络传输流程、地址管理)

文章目录 1. 认识 协议2. 了解 网络协议2.1 引入 协议分层2.2 OSI 七层模型 与 TCP/IP 四层模型 3. 网络传输 流程&#xff01;&#xff01;&#xff01;3.1 网络传输流程图3.2 关于报头3.3 实例解释 传输过程&#xff08;封装与解包&#xff09; 4. 网络中的地址管理4.1 认识 …

力扣串题:字符串中的第二大数字

此题的精妙之处在于char类型到int类型的转化&#xff0c;需要运算来解决 int secondHighest(char * s) {int max1-1;int max2-1;int szstrlen(s);int i 0 ;for(i0;i<sz;i){if(s[i]>0&&s[i]<9){if((s[i]-0)>max1){max2max1;max1s[i]-0;}else if((s[i]-0)&l…

Linux I2C调试分享

I2C简介 I2C&#xff08;Inter-Integrated Circuit&#xff09;是一种多主机、两线制、串行计算机总线&#xff0c;用于连接低速外围设备到处理器或微控制器。这种通信协议由Philips Semiconductor&#xff08;现在的NXP Semiconductors&#xff09;在1980年代初期开发。 I2C…

英语四六级有线调频听力广播-厦门华厦学院有线调频听力广播系统建设深度解析

英语四六级有线调频听力广播-厦门华厦学院有线调频听力广播系统建设深度解析 由北京海特伟业任洪卓发布于2024年3月14日 随着社会的快速发展和国际交流的日益频繁&#xff0c;英语已成为我们日常生活中不可或缺的一部分。作为衡量大学生英语水平的重要标准之一&#xff0c;大学…

javaweb数据传参类型(2)

前言 友友们好呀&#xff0c;今天来分享一下对于各种数据类型传参的问题&#xff0c;今天陪伴我们的云海 目录 前言 数组集合传参 补充 日期参数 补充 Json格式数据传参 补充 路径参数 补充 今日分享 ​​​​​​​数组集合传参 类似于我们之前进行的简单的参数传递…

深度学习模型部署(五)onnx模型以及相应工具

ONNX概念 onnx不仅仅一种模型参数存储的格式&#xff0c;还是一套完整的用于描述计算函数的编程语言&#xff0c;它的作用就是定义计算图&#xff0c;他本身无法进行。 这个概念和Verilog有点像&#xff0c;一个是硬件描述语言&#xff0c;一个是模型描述语言。 onnx模型或者说…

Learn OpenGL 10 Assimp+网格+模型

Assimp 一个非常流行的模型导入库是Assimp&#xff0c;它是Open Asset Import Library&#xff08;开放的资产导入库&#xff09;的缩写。Assimp能够导入很多种不同的模型文件格式&#xff08;并也能够导出部分的格式&#xff09;&#xff0c;它会将所有的模型数据加载至Assim…

git基础命令(一)

目录 基础概念git statusgit addgit diffgit loggit commit文件可以处于以下三种状态之一远程存储库与本地存储库参考 用于知识记录。后续有新的的内容&#xff0c;例子&#xff0c;将持续更新本文档。 基础概念 工作树&#xff1a;git add 之前&#xff0c;变动内容的文件列表…

经典数组和指针笔试题解析——C语言

【本节内容】 1. 数组和指针笔试题解析 2. 指针运算笔试题解析 1. 数组和指针笔试题解析 1.1 一维数组 #include <stdio.h> int main() {int a[] { 1,2,3,4 };printf("%zd\n", sizeof(a));printf("%zd\n", sizeof(a 0));printf("%zd\n&qu…

【金三银四】掌趣科技24.3.7 H项目 服务端开发笔试题

考试题型&#xff1a; 不定项选择题 10 道 &#xff0c; 填空题 10 道 &#xff0c; 问答题 2 道 &#xff0c; 编程题 4 道 目录 不定项选择题 10 道填空题 10 道问答题 2 道编程题 4 道 不定项选择题 10 道 在TCP协议中&#xff0c;发送方的窗口大小是由两个关键因素共同决定…

三个表联合查询的场景分析-场景1:a表关联了b表和c表

本场景对应情景如下&#xff1a; 三个数据表&#xff0c;一个表的两个字段分别关联了另外两个表各自的id数据&#xff0c;可能包含多个id&#xff08;两个1对多关联&#xff09;。 目录 数据表准备 需求1、查询c表的列表数据&#xff0c;要求获得关联的b表中的name&#xf…

工业界真实的推荐系统(小红书)-涨指标的方法:召回、排序、多样性、特殊人群、利用交互行为

课程特点&#xff1a;系统、清晰、实用&#xff0c;原理和落地经验兼具 b站&#xff1a;https://www.bilibili.com/video/BV1HZ421U77y/?spm_id_from333.337.search-card.all.click&vd_sourceb60d8ab7e659b10ea6ea743ede0c5b48 讲义&#xff1a;https://github.com/wangsh…

CSDN 编辑器设置图片缩放和居中

CSDN 编辑器设置图片缩放和居中 文章目录 CSDN 编辑器设置图片缩放和居中对齐方式比例缩放 对齐方式 Markdown 编辑器插入图片的代码格式为 ![图片描述](图片路径)CSDN 的 Markdown 编辑器中插入图片&#xff0c;默认都是左对齐&#xff0c;需要设置居中对齐的话&#xff0c;…

项目性能优化—性能优化的指标、目标

项目性能优化—性能优化的指标、目标 性能优化的终极目标是什么 性能优化的目标实际上是为了更好的用户体验&#xff1a; 一般我们认为用户体验是下面的公式&#xff1a; 用户体验 产品设计&#xff08;非技术&#xff09; 系统性能 ≈ 系统性能 快 那什么样的体验叫快呢…

STM32第九节(中级篇):RCC——时钟树讲解(第一节)

目录 前言 STM32第九节&#xff08;中级篇&#xff09;&#xff1a;RCC——时钟树讲解 时钟树主系统时钟讲解 HSE时钟 HSI时钟 锁相环时钟 系统时钟 SW位控制 HCLK时钟 PCLKI时钟 PCLK2时钟 RTC时钟 MCO时钟输出 6.2.7时钟安全系统(CSS&#xff09; 小结 前言 从…

基于HarmonyOS ArkTS中秋国庆祝福程序、以代码之名,写阖家团圆祝福

中秋、国庆双节将至&#xff0c;作为程序员&#xff0c;以代码之名&#xff0c;表达对于阖家团圆的祝福。本节将演示如何在基于HarmonyOS ArkUI的SwiperController、Image、Swiper等组件来实现节日祝福轮播程序。 规则要求具体要求如下&#xff1a; 1、根据主题&#xff0c;用…

遗嘱消息(Will Message)介绍与示例 _ MQTT 5.0 特性详解

什么是 MQTT 遗嘱消息&#xff1f; 在现实世界中&#xff0c;一个人可以制定一份遗嘱&#xff0c;声明在他去世后应该如何分配他的财产以及应该采取什么行动。在他去世后&#xff0c;遗嘱执行人会将这份遗嘱公开&#xff0c;并执行遗嘱中的指示。 在 MQTT 中&#xff0c;客户端…

honle电源维修UV电源控制器维修EVG EPS60

好乐UV电源控制器维修&#xff1b;honle控制器维修&#xff1b;UV电源维修MUC-Steuermodul 2 LΛmpen D-82166 主要维修型号&#xff1a; EVG EPS 60/120、EVG EPS 100、EVG EPS200、EVG EPS 220、EVG EPS 340、EVG EPS40C-HMI、EVG EPS60 HONLE好乐uv电源维修故障包括&#…