我需要从字符串中提取给定键的值。我做了这个快速尝试:
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
实际上来自函数参数。)
答案 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)
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=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;
}
示例输出:
$ ./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”字符串。机会很小,但你可能会认为你需要担心(它会阻止这些代码防弹)。