【问题标题】:Extract string from JSON in C从C中的JSON中提取字符串
【发布时间】:2017-05-03 07:37:40
【问题描述】:

我有一个选择和提取 JSON 行的函数。该 JSON 行将在另一个函数中计算,该函数应该提取它的值。

"key" : "value",

我希望在不使用任何用于操作 JSON 的库的情况下提取

到目前为止,我的代码如下所示:

char* extractValueInLine(char* line) { 
  if(!verifyLine(line)) // Checks wether line contains 4 quotes or not
    return "";
  int len = strlen( line );
  char* res = NULL;
  unsigned quoteCpt = 0;
  for (unsigned i = 0; i < len; i++){
    if (line[i] == '\"')
        quoteCpt++;
    if (quoteCpt == 3) // If 3 quotes has been skipped
    {
        res = malloc((char) sizeof(res) + sizeof(char)); // Adding memory for one char
        if (NULL == res)
            fprintf(stderr, "Not enough memory.\n");
        else
        {
            char toAppend[2];
            toAppend[1] = '\0';
            toAppend[0] = line[i];
            strcat(res, toAppend); // Append current char 
        }
    }
    return res;
}

因为输出是空白而不是 value,所以这非常难看而且根本没有效率。 尽管如此,我已经尝试了越来越多的方法来做到这一点,使用字符串库函数以及 sscanf、strtok 和其他东西,但它要么不起作用,要么很容易被破坏。
即使添加或缺少空格也可以工作的代码将是完美的。
如果有人可以建议我或告诉我我在这里缺少什么。

【问题讨论】:

  • 你为什么不使用一些库?或者它是某些任务的一部分?
  • malloc((char) sizeof(res) + sizeof(char)) 看起来很可疑。 sizeof(res) 是指针的大小,而不是要包含在那里的字符串。你应该使用类似malloc(len-i+1)的东西。
  • len 包含参数 line 的大小,该大小大于 res 应有的大小。我想要的是通过迭代为当前的 char 迭代添加内存。另外,不使用库确实是作业的一部分,因为我的 JSON 相关代码很少,而且似乎不值得使用。
  • JSON 的好处之一是自动反序列化。 js、java 和 C# 等高级语言通过反射(自动计算出类和属性名称)来处理这个问题。如果没有一大堆包装宏,用 C 实现会非常难看。
  • 不返回"",而是返回NULL。

标签: c json string memory


【解决方案1】:

使用strchr() 查找引号的位置。然后,使用该信息提取值。

类似

char *q1 = strchr(line, '\"'); /* needs error checking */
char *q2 = strchr(q1 + 1, '\"');
char *q3 = strchr(q2 + 1, '\"');
char *q4 = strchr(q3 + 1, '\"');

/* allocate (q4 - q3) bytes for res */
sprintf(res, "%.*s", (int)(q4 - q3 - 1), q3 + 1);

【讨论】:

  • 我刚刚运行了你的代码,答案是正确的。虽然,我收到这条消息:警告:字段精度说明符“。*”需要“int”类型的参数,但参数 3 的类型为“long int”[-Wformat=]。你能解释一下这是如何工作的吗? q4-q3-1 似乎是值的长度,而 q3+1 是值的内存地址。格式说明符如何处理 2 个值?
  • 转换值(代码已编辑)以更正错误(并抑制警告)。至于转换说明符中的.*,它使用int 并限制复制的字符数。
  • 所以这有点类似于 sprintf(res, "%.3s", q3+1);但是 .* 转换说明符允许使用整数。好的!!!! (00)
  • 就是这样!很高兴你明白:-)
  • @Badda:你需要q4 - q3(不是q4 - q3 - 1)字节来说明零字符串终止符。
【解决方案2】:

代码的问题

  1. 缺少一个 },这会使您的代码在第一次迭代中返回。
  2. 您每次都在分配新空间。这使它失去了以前的内容。

解决办法是

char* extractValueInLine(char* line) { 
    int len = strlen( line );
    char* res = malloc(1);
    res[0] = '\0';
    unsigned quoteCpt = 0;
    for (unsigned i = 0; i < len; i++){
        if (line[i] == '\"')
            quoteCpt++;
        else if (quoteCpt == 3) {
            res = realloc(res, strlen(res) + sizeof(char) + 1); // Free memory for additional char
            if (NULL == res)
                fprintf(stderr, "Not enough memory.\n");
            else{
                char toAppend[2];
                toAppend[1] = '\0';
                toAppend[0] = line[i];
                strcat(res, toAppend);
            }
        }
    }
    return res;
}

主要的变化是我使用了realloc 而不是malloc,它复制了以前的内容并释放了旧缓冲区。

您可以在Ideone查看演示

【讨论】:

  • 您的解决方案似乎工作得很好,除了当我修改键和值时,一半时间出现未定义错误,另一半出现“内存不足”。
  • 你尝试了什么输入?
  • @AjayBrahmakshatriya - realloc() 可以从当前位置分配。如果是这种情况,它不一定会释放旧内存。
  • @Nguaial 是的,当然。我的意思是说,如果它必须被释放,它就被释放了,他不必担心释放。无论如何,这段代码效率很低。我只是想用尽可能少的改动来修复他的程序。
  • 嗯,一次又一次地重新分配的方法不是很有效,可能会导致这样的错误。为什么不运行两个循环。第一个循环将只计算值的长度。然后分配所需的空间,然后开始填充它。如果您想不通,我可以进行编辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多