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

2024-03-15 04:44

本文主要是介绍【CSP试题回顾】201709-3-JSON查询,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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中要调用ProcessPropertyContentstring 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查询

这篇关于【CSP试题回顾】201709-3-JSON查询的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

MySQL存储过程之循环遍历查询的结果集详解

《MySQL存储过程之循环遍历查询的结果集详解》:本文主要介绍MySQL存储过程之循环遍历查询的结果集,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言1. 表结构2. 存储过程3. 关于存储过程的SQL补充总结前言近来碰到这样一个问题:在生产上导入的数据发现

Springboot3+将ID转为JSON字符串的详细配置方案

《Springboot3+将ID转为JSON字符串的详细配置方案》:本文主要介绍纯后端实现Long/BigIntegerID转为JSON字符串的详细配置方案,s基于SpringBoot3+和Spr... 目录1. 添加依赖2. 全局 Jackson 配置3. 精准控制(可选)4. OpenAPI (Spri

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA

MYSQL查询结果实现发送给客户端

《MYSQL查询结果实现发送给客户端》:本文主要介绍MYSQL查询结果实现发送给客户端方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql取数据和发数据的流程(边读边发)Sending to clientSending DataLRU(Least Rec

MySQL复杂SQL之多表联查/子查询详细介绍(最新整理)

《MySQL复杂SQL之多表联查/子查询详细介绍(最新整理)》掌握多表联查(INNERJOIN,LEFTJOIN,RIGHTJOIN,FULLJOIN)和子查询(标量、列、行、表子查询、相关/非相关、... 目录第一部分:多表联查 (JOIN Operations)1. 连接的类型 (JOIN Types)

python编写朋克风格的天气查询程序

《python编写朋克风格的天气查询程序》这篇文章主要为大家详细介绍了一个基于Python的桌面应用程序,使用了tkinter库来创建图形用户界面并通过requests库调用Open-MeteoAPI... 目录工具介绍工具使用说明python脚本内容如何运行脚本工具介绍这个天气查询工具是一个基于 Pyt

Java中JSON格式反序列化为Map且保证存取顺序一致的问题

《Java中JSON格式反序列化为Map且保证存取顺序一致的问题》:本文主要介绍Java中JSON格式反序列化为Map且保证存取顺序一致的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未... 目录背景问题解决方法总结背景做项目涉及两个微服务之间传数据时,需要提供方将Map类型的数据序列化为co

MyBatis编写嵌套子查询的动态SQL实践详解

《MyBatis编写嵌套子查询的动态SQL实践详解》在Java生态中,MyBatis作为一款优秀的ORM框架,广泛应用于数据库操作,本文将深入探讨如何在MyBatis中编写嵌套子查询的动态SQL,并结... 目录一、Myhttp://www.chinasem.cnBATis动态SQL的核心优势1. 灵活性与可

Mybatis嵌套子查询动态SQL编写实践

《Mybatis嵌套子查询动态SQL编写实践》:本文主要介绍Mybatis嵌套子查询动态SQL编写方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、实体类1、主类2、子类二、Mapper三、XML四、详解总结前言MyBATis的xml文件编写动态SQL