遍历并修改C json字符串

2024-02-08

在 C 中遍历和修改 JSON 字符串的正确方法是什么?

具体来说,我有一个字符串,body_buf。打印出来时

print("length: %d\n%.*s\n", body_len, body_len, body_buf);

它看起来像这样:

length: 113
{"field1":"something","whatever":10,"description":"body","id":"random","__oh__":{"session":"12345678jhgfdrtyui"}}

另一个更复杂的 body_buf 可能如下所示:

{"status":1,"query":{},"proc":{"memory":{"total":17177939968,"cmax":18363625472,"amax":20000000000},"cpu":{"cores":[0.788,0.132,0.319,2.951,10.111,3.309,1.43,0.8,2.705,4.203,2.32,2,0.019,0.172,0.247,3.888,0.282,0.423,5.254,0.258,0.009,0.369,3.277,0.048,0.283,7.574,3.086,1.592,0.191,0.166,4.348,0.391,0.085,0.25,7.12,4.927,3.671,1.147,3.216,4.628,0.131,0.995,0.744,4.252,4.022,3.505,3.758,3.491],"total":108.886,"limit":800},"disk":{"used":20170,"limit":50000,"io_limit":500}}}

我想根据以下规则简化 body_buf (也兼作删除敏感信息),仅修改值,而不修改任何键:

  1. 字符串变成字符串的长度。
  2. 字符串数组变为 [array_len, max_len, min_len]。
  3. 数字数组变为 [array_len, max, min]。

我不熟悉在 C 中使用 JSON 字符串。执行此操作的最佳方法是什么?

我可以将 body_buf 视为一个字符串并遍历它,修改“:”后面的任何内容,因为这些必然是我可能修改的值,具体取决于类型。对于数组,我需要跟踪夹在“[”和“]”之间的任何内容。这可能可行,但看起来并不那么简单。

或者,也许将 body_buf 转换为 JSON 类型,然后遍历嵌套结构。但后来我也必须修改它。我还没有找到一个使用 json-c 或其他方式遍历和修改(或通过某种深层复制创建一个新的?) JSON 对象的 C 示例(这会很有帮助)。

抛开细节(上面的规则,1-3)不谈,这应该是一个相对常见的操作——遍历和修改。因此,对于那些更了解 C 中 json-c 或 JSON 操作的复杂性和良好/标准实践的人,我正在寻找一些指针。

同样,我有 json-c:

#include "cJSON.h"
#include "cJSON_Utils.h"
#include <libjson/json.h>
#include <libjson/json_tokener.h>

目前我查到的相关信息包括:

https://gist.github.com/alan-mushi/19546a0e2c6bd4e059fd https://gist.github.com/alan-mushi/19546a0e2c6bd4e059fd

如何在 json_tokener_parse() 之后获取 json 值? https://stackoverflow.com/questions/14879876/how-to-get-json-values-after-json-tokener-parse

使用 json-c 解析深度嵌套的 JSON 键 https://stackoverflow.com/questions/29555192/parsing-deeply-nested-json-key-using-json-c


我不知道“简化”json 有什么用处。 第一次在 c 中使用 json 可能会很可怕。

I like cJSON库,轻便、便携、稳定。 它具有良好的测试覆盖率,并且许可证是 MIT。

我认为这段代码使用了库cJSON会做你要求的事情:

#include <cjson/cJSON.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <limits.h>
#include <float.h>

const char json1[] = "{\"field1\":\"something\",\"whatever\":10,\"description\":\"body\",\"id\":\"random\",\"__oh__\":{\"session\":\"12345678jhgfdrtyui\"}}";
const char json2[] = "{\"status\":1,\"query\":{},\"proc\":{\"memory\":{\"total\":17177939968,\"cmax\":18363625472,\"amax\":20000000000},\"cpu\":{\"cores\":[0.788,0.132,0.319,2.951,10.111,3.309,1.43,0.8,2.705,4.203,2.32,2,0.019,0.172,0.247,3.888,0.282,0.423,5.254,0.258,0.009,0.369,3.277,0.048,0.283,7.574,3.086,1.592,0.191,0.166,4.348,0.391,0.085,0.25,7.12,4.927,3.671,1.147,3.216,4.628,0.131,0.995,0.744,4.252,4.022,3.505,3.758,3.491],\"total\":108.886,\"limit\":800},\"disk\":{\"used\":20170,\"limit\":50000,\"io_limit\":500}}}";
const char json3[] = "{\"Name\":\"Tom\",\"Age\":18,\"Address\":\"California\",\"arr\":[1,2,3,4,5]}";

static void simplifyArray(cJSON *input, cJSON *output)
{  
    cJSON *item;
    size_t noElems = 0;
    
    if (cJSON_IsString(cJSON_GetArrayItem(input, 0))) {
        size_t max, min;
        max = 0;
        min = UINT_MAX;
        cJSON_ArrayForEach(item, input) {
            noElems++;
            size_t len = strlen(cJSON_GetStringValue(item));
            if (len > max) max = len;
            if (len < min) min = len;
        }
        cJSON *newArray = cJSON_AddArrayToObject(output, input->string);
        cJSON_AddItemToArray(newArray, cJSON_CreateNumber(noElems));
        cJSON_AddItemToArray(newArray, cJSON_CreateNumber(max));
        cJSON_AddItemToArray(newArray, cJSON_CreateNumber(min));

    } else if (cJSON_IsNumber(cJSON_GetArrayItem(input, 0))) {
        double max, min;
        max = -DBL_MAX;
        min = DBL_MAX;
        cJSON_ArrayForEach(item, input) {
            noElems++;
            double value = item->valuedouble;
            if (value > max) max = value;
            if (value < min) min = value;
        }
        cJSON *newArray = cJSON_AddArrayToObject(output, input->string);
        cJSON_AddItemToArray(newArray, cJSON_CreateNumber(noElems));
        cJSON_AddItemToArray(newArray, cJSON_CreateNumber(max));
        cJSON_AddItemToArray(newArray, cJSON_CreateNumber(min));
    }
}

static void simplify(cJSON *input, cJSON *output)
{
    cJSON *elem;
    for (elem = input; elem != NULL; elem = elem->next) {
        if (cJSON_IsString(elem)) {
            cJSON_AddNumberToObject(output, elem->string, strlen(cJSON_GetStringValue(elem)));
        } else if (cJSON_IsArray(elem)) {
            simplifyArray(elem, output);
        } else if (cJSON_IsObject(elem)) {
            cJSON *newOutput = cJSON_AddObjectToObject(output, elem->string);
            simplify(elem->child, newOutput);
        } else {
            cJSON *dup = cJSON_Duplicate(elem, true);
            cJSON_AddItemToObject(output, elem->string, dup);
        }
    }
}

static void simplifyAndPrint(const char *json)
{
    cJSON *input = cJSON_Parse(json);
    cJSON *output = cJSON_CreateObject();
    simplify(input->child, output);
    printf("%s\n", cJSON_PrintUnformatted(output));
    cJSON_Delete(input);
    cJSON_Delete(output);
}

int main()
{
    simplifyAndPrint(json1);
    simplifyAndPrint(json2);
    simplifyAndPrint(json3);
    return 0;
}

输出:

{"field1":9,"whatever":10,"description":4,"id":6,"__oh__":{"session":18}}
{"status":1,"query":{},"proc":{"memory":{"total":17177939968,"cmax":18363625472,"amax":20000000000},"cpu":{"cores":[48,10.111,0.009],"total":108.886,"limit":800},"disk":{"used":20170,"limit":50000,"io_limit":500}}}
{"Name":3,"Age":18,"Address":10,"arr":[5,5,1]}

在上面的示例中,我首选不要更改输入 JSON,如果您不关心这一点,您可以使用该函数cJSON_ReplaceItemInObject来替换节点。

P.S.:我假设数组仅包含字符串和数字,并且不要混合它们,因为没有规则来处理其他数组配置。

P.S.2:此代码使用 Ubuntu 20.04 中存在的库版本,如果您从 GitHub 下载该库,该版本将包含更多功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

遍历并修改C json字符串 的相关文章

随机推荐

  • JFrame 着色应该像这张图片

    我的问题有点奇怪 我希望我创建的表单 使用 JFrame 颜色应该类似于这张图片 我应该使用特殊的外观和感觉吗 我应该使用特殊的外观和感觉吗 据我所知 没有这样的内置外观和感觉可用 然而对于 外观和感觉 来说 Look 指 GUI 小部件
  • 用距离随机整数填充数组

    我需要一个数组来填充随机整数 这些整数应该彼此非常不同 即每个项目之间必须至少有 20 个单位的间隔 这是我到目前为止所尝试过的 var all var i 0 randomDiff function randomDiff var num1
  • 如何向 ode45 传递一个带有两个参数的 odefun ?

    我有一个用例如下 Inside F m我有一个函数F以 a 作为其参数2 x 1 matrix x F需要对矩阵进行矩阵乘法kmat by x kmat是由脚本生成的变量 所以 我所做的事情已经确定kmat在脚本中成为全局 global k
  • 如何在 C++ 中打印方法指针的地址?

    例如 struct A void m void stream print void A p void A m std cerr lt lt p lt lt std endl void printf print void A p void A
  • 在 Bash 脚本中指定 sftp 的密码 [重复]

    这个问题在这里已经有答案了 我正在尝试编写一个脚本来通过 SFTP 备份文件 问题是 它需要密码 而且我认为没有办法手动指定 SFTP 的密码 我听说过使用公钥不需要密码 但这需要能够 ssh 进入远程服务器并修改一些配置文件 而我无法做到
  • Servlet 到 jsp 通信最佳实践

    我正在学习如何在谷歌应用程序引擎上编写java servlet 和jsp 页面 我正在尝试使用 MVC 模型 但我不确定我做得是否正确 目前 我有一个在访问页面时调用的 servlet servlet 完成所有处理并创建一个 HomePag
  • 检查 Swift 中的网络状态,找不到接受提供的参数的“~=”重载

    我在用着可达性 h库来检查我的 swift 应用程序中的网络状态 我在 案例 行中遇到了这个问题 找不到接受提供的 重载 论点 我该如何解决它 func checkNetworkStatus var reachability Reachab
  • 为什么这个查询不返回 10 行?

    我在一个唯一的列上连接两个表 这两个表都包含 10 行 我知道桌子cte可以有重复项 但仍然应该有10结果中的记录 请参阅DBFIDLE1 https dbfiddle uk C3fkuh3s with ints as select 1 a
  • 在 Visual Studio for Mac 17.5 预览版中找不到 SDK Microsoft.NET.Sdk

    当我想从 VS 2022 for Mac 17 5 预览版中的模板创建新的 MonoGame iOS 项目时 收到此错误消息 What is missing in Preferences What should I install None
  • ASP.NET 预编译期间出现类型解析错误

    在 NET 3 5 Web 应用程序的 ASP NET 预编译过程中 各种初始化在类型初始值设定项中执行 当环境配置不正确时 类型初始值设定项之一会引发自定义异常 但是 当抛出我们的自定义异常时 aspnet compiler exe 会告
  • 自动调用 Silverlight 行为的 OnDetaching()

    我在 silverlight 控件上使用了多种混合行为和触发器 我想知道是否有任何机制可以自动分离或确保当不再使用控件 即从可视化树中删除 时为行为或触发器调用 OnDetaching 我的问题是 由于其中一种行为 控件存在托管内存泄漏 该
  • 如何设置 ArrayList 中对象的变量值

    我正在执行一项任务 我必须 创建一个具有以下属性 变量的 Employee 类 姓名 年龄 部门 创建一个名为 Department 的类 其中将包含员工列表 A Department 类将有一个方法返回按年龄排序的员工 b 部门的值只能是
  • 如何在Python中给定时间后结束程序运行

    我希望我的 Python 程序运行一个算法给定的秒数 然后打印迄今为止最好的结果并结束 最好的方法是什么 我尝试了以下方法 但没有成功 程序在打印后继续运行 def printBestResult self print self bestR
  • 将 HTML 字符串添加到 OpenXML (*.docx) 文档

    我正在尝试使用 Microsoft 的 OpenXML 2 5 库来创建 OpenXML 文档 一切都运行良好 直到我尝试将 HTML 字符串插入到我的文档中 我已经在网上搜索过 这是我到目前为止所想到的 只截取我遇到问题的部分 Parag
  • wkHTMLtoPDF 支持@page 规则吗?

    我一直在尝试使用这个简单的命令来探索 wkHTML2PDF 的功能 wkhtml2pdf test htm test pdf 它似乎不支持可能包含在附加 CSS 文件中的 page 规则 或者我错过了什么 一些参数的例子 简而言之 答案是否
  • MediaPlayer,仅视频 m3u8 HTML 流有效

    我正在将 MediaPlayer 与 m3u8 音频流一起使用 这会导致日志错误消息 Error 1 1010 当我查看错误代码时 第一个参数似乎没问题 https github com android platform external
  • C# 功能请求:在匿名类型上实现接口

    我想知道需要什么才能使这样的事情发挥作用 using System class Program static void Main var f new IFoo Foo foo Print gt Console WriteLine Foo i
  • python“set.intersection”对于n个集合的时间复杂度

    我想知道该问题的复杂性set intersection蟒蛇 我查看了 python 的文档和在线 wiki 但没有找到该方法对于多组的时间复杂度 The python wiki 关于时间复杂度列表 https wiki python org
  • 为 ComboBox 项目分配值

    我目前正在尝试为 winform 的货币制作一个下拉框 组合框 这是我到目前为止所拥有的 但我注意到下拉框的数据绑定版本有一个特殊选项 所以我想知道是否可以创建与此类似的东西 而无需对整个字符串进行比较或在数据库中创建表 列表和组合框可以包
  • 遍历并修改C json字符串

    在 C 中遍历和修改 JSON 字符串的正确方法是什么 具体来说 我有一个字符串 body buf 打印出来时 print length d n s n body len body len body buf 它看起来像这样 length 1