Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用C中的scanf提取key=值_C_String_Scanf - Fatal编程技术网

用C中的scanf提取key=值

用C中的scanf提取key=值,c,string,scanf,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]; k

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

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=%s
param_name
实际上来自函数参数)。

不是直接的,不是

实际上,没有什么可以阻止您在运行时为
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;
    }
  }
}
void print\u值(常量字符**js,大小\u t num\u js,常量字符*键)
{
字符tmp[32],值[32];
snprintf(tmp,tmp的大小,“%s=%%31s”,键);
对于(大小i=0;i
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“
愚弄了


注意:到目前为止,所有答案都存在不解析空字符串的弱点。

需要考虑的一个问题是,在字符串中查找特定键值的“key=value”设置(如问题中的
param_2
)与在字符串中查找任何“key=value”设置(事先没有考虑特定的键)之间存在差异。使用的技术是相当不同的

另一个未被明显考虑的问题是,您可能正在寻找一个键
param_2
,但字符串还包含
param_22=xyz
t_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;
}

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

我认为,您的
sscanf
调用复制太多,如果值不是最后一个条目,您可能需要
%31[^\n]“
?@mafso,%s当然会在碰到白色字符时停止。抱歉这个愚蠢的评论。请注意,它“有效”,因为在
参数2=321
条目之前没有
参数22=xyz
条目(或
备用参数2=abc
条目)。您最好使用正则表达式库或其他解析器。尽管scanf允许实现定义的正则表达式行为,但依赖它是脆弱的。
$ ./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]
$