使用C中的scanf提取key = value

时间:2014-06-30 12:41:44

标签: c string scanf

我需要从字符串中提取给定键的值。我做了这个快速尝试:

char js[] = "some preceding text with\n"
    "new lines and spaces\n"
    "param_1=123\n"
    "param_2=321\n"
    "param_3=string\n"
    "param_2=321\n";

char* param_name = "param_2";
char *key_s, *val_s;
char buf[32];

key_s = strstr(js, param_name);

if (key_s == NULL)
    return 0;

val_s = strchr(key_s, '=');

if (val_s == NULL)
    return 0;

sscanf(val_s + 1, "%31s", buf);

printf("'%s'\n", buf);

它实际上运作正常(printf给出'321')。但我认为scanf / sscanf会使这项任务变得更加容易,但我还是没有设法找出格式化字符串。

是否可以将变量param_name的内容传递给sscanf,以便将其作为格式化字符串的一部分进行评估?换句话说,我需要指示sscanf在这种情况下它应该寻找模式param_2=%sparam_name实际上来自函数参数。)

3 个答案:

答案 0 :(得分:1)

不直接,没有。

在实践中,当然没有什么可以阻止您在运行时为sscanf()构建格式字符串,例如, snprintf()

类似的东西:

void print_value(const char **js, size_t num_js, const char *key)
{
  char tmp[32], value[32];

  snprintf(tmp, sizeof tmp, "%s=%%31s", key);
  for(size_t i = 0; i < num_js; ++i)
  {
    if(sscanf(js[i], tmp, value) == 1)
    {
      printf("found '%s'\n", value);
      break;
    }
  }
}

答案 1 :(得分:1)

OP有一个很好的第一步:

char *key_s = strstr(js, param_name);
if (key_s == NULL)
  return 0;

其余部分可以简化为

if (sscanf(&key_s[strlen(param_name)], "=%31s", buf) == 0) {
  return 0;
}
printf("'%s'\n", buf);

或者,可以使用" =%31s"=之前允许空格。

OP的方法被"param_2 321\n" "param_3=string\n"愚弄了。

注意:到目前为止,所有答案都无法解析空字符串。

答案 2 :(得分:1)

需要考虑的一个问题是在字符串中为特定键值(例如问题中的param_2)找到“key = value”设置与查找任何“key = value”设置之间的区别在字符串中(没有特定的密钥,先验)。使用的技术有很大不同。

另一个没有明显考虑过的问题是您可能正在寻找密钥param_2,但该字符串还包含param_22=xyzt_param_2=abc。使用strstr()寻找param_2的简单方法将会选择其中任何一种方法。

在示例数据中,有一组字符不是'key = value'格式,要在任何'key = value'部分之前跳过。在一般情况下,我们应该假设这些数据出现在'key = value'对之前,之间和之后。似乎值不需要支持引用字符串和元字符等复杂性,并且值由空格分隔。没有可见的评论惯例。

这是一些可行的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum { MAX_KEY_LEN = 31 };
enum { MAX_VAL_LEN = 63 };

int find_any_key_value(const char *str, char *key, char *value);
int find_key_value(const char *str, const char *key, char *value);

int find_any_key_value(const char *str, char *key, char *value)
{
    char junk[256];
    const char *search = str;
    while (*search != '\0')
    {
        int offset;
        if (sscanf(search, " %31[a-zA-Z_0-9]=%63s%n", key, value, &offset) == 2)
            return(search + offset - str);
        int rc;
        if ((rc = sscanf(search, "%255s%n", junk, &offset)) != 1)
            return EOF;
        search += offset;
    }

    return EOF;
}

int find_key_value(const char *str, const char *key, char *value)
{
    char found[MAX_KEY_LEN + 1];
    int offset;
    const char *search = str;
    while ((offset = find_any_key_value(search, found, value)) > 0)
    {
        if (strcmp(found, key) == 0)
            return(search + offset - str);
        search += offset;
    }
    return offset;
}

int main(void)
{
    char js[] = "some preceding text with\n"
                "new lines and spaces\n"
                "param_1=123\n"
                "param_2=321\n"
                "param_3=string\n"
                "param_4=param_2=confusion\n"
                "m= x\n"
                "param_2=987\n";
    const char p2_key[] = "param_2";
    int offset;
    const char *str;
    char key[MAX_KEY_LEN + 1];
    char value[MAX_VAL_LEN + 1];

    printf("String being scanned is:\n[[%s]]\n", js);

    str = js;
    while ((offset = find_any_key_value(str, key, value)) > 0)
    {
        printf("Any found key = [%s] value = [%s]\n", key, value);
        str += offset;
    }

    str = js;
    while ((offset = find_key_value(str, p2_key, value)) > 0)
    {
        printf("Found key %s with value = [%s]\n", p2_key, value);
        str += offset;
    }

    return 0;
}

示例输出:

$ ./so24490410
String being scanned is:
[[some preceding text with
new lines and spaces
param_1=123
param_2=321
param_3=string
param_4=param_2=confusion
m= x
param_2=987
]]
Any found key = [param_1] value = [123]
Any found key = [param_2] value = [321]
Any found key = [param_3] value = [string]
Any found key = [param_4] value = [param_2=confusion]
Any found key = [m] value = [x]
Any found key = [param_2] value = [987]
Found key param_2 with value = [321]
Found key param_2 with value = [987]
$

如果需要处理不同的键或值长度,则需要调整格式字符串以及枚举。如果将键缓冲区的大小和值缓冲区的大小传递给函数,则需要使用snprint()来创建sscanf()使用的格式字符串。您可能只有255个字符的单个“单词”,紧跟目标“key = value”字符串。机会很小,但你可能会认为你需要担心(它会阻止这些代码防弹)。