sscanf
来检查一个字符串是否符合给定的格式。为此,我提供了在格式字符串中参数的数量,并检查当解析输入时sscanf
返回相同的数量。作为一个基本的解析器,我想检查一个字符串是否与多个格式之一匹配。由于
sscanf
函数是可变参的,所以我如何处理需要传递的不同数量的参数?目前,我只是向函数传递了非常大的参数(例如50),并希望格式字符串不包含更多的参数。
有没有更好的方法来处理这个问题?
char txt[] = "232343341235898dfsfgs/.f";
regex_t reg;
regmatch_t refs[MAX_REFS]; //as in, the maximum number of data you want to extract
regcomp(®, "3433\\([0-5]*\\).*", 0); //replace 0 with REG_EXTENDED if desired
regexec(®, txt, MAX_REFS, refs, 0);
regfree(®);
txt[refs[0].rm_eo+1] = '\0';
int n = atoi(txt+refs[0].rm_so);
printf("%d\n", n);
41235
regex.h
将是我的下一个选择。我能否像sscanf
一样使用regex.h
将输入解析为不同的变量,还是我必须同时使用regex.h
和sscanf
? - ryystregexec
。我将添加一个示例。 - Dave您可以使用stdarg.h
中提供的宏,使用可变长度参数编写验证函数。
例如,
int my_validation_func(const char *format, ...) {
va_list ap;
char *p, *sval;
int ival;
float fval;
va_start(ap, format);
for(p=format; *p ; p++) {
if (*p != '%') {
continue;
}
switch(*++p) {
case 'd':
ival = va_arg(ap, int);
break;
case 'f':
fval = va_arg(ap, float);
break;
case 's':
for (sval = va_arg(ap, char *); *sval; sval++);
break;
default:
break;
}
}
va_end(ap);
}
希望这能帮到你!
你应该使用lex/yacc来构建一个合适的解析器。或者,首先使用strtok
对字符串进行分词可能会简化你的问题。(注意:正确使用strtok
非常棘手--请仔细阅读其文档。)
不太有用的答案是“不要那样做,正确地编写解析器,可以使用lex和/或yacc或bison”。
你所问的问题的答案是“是的,你可以这样做”。我认为没有任何理由不能有比格式要求更多的可变参数,尽管太少会是一件坏事。我假设你有一个可能格式的数组或列表,并在循环中调用sscanf。
如果你在编写代码时不知道参数的数量和类型,sscanf()
就无法安全地执行你想要的操作。
向 sscanf()
传递50个参数是可以的(未被格式字符串消耗的参数将被评估但忽略),但是与格式字符串对应的参数必须是预期类型(在提升后);否则,行为是未定义的。所以,如果你想检测一个字符串是否可以使用 "%d"
或 "%f"
进行扫描,就不能只用一次 sscanf()
调用安全地完成。(可能可以通过传递指向足够大的缓冲区的 void*
来解决问题,但行为仍然是未定义的。)
sscanf()
的另一个麻烦问题是它不能处理数值溢出。如下:
char *s = "9999999999999999999999999";
int n;
int result = sscanf(s, "%d", &n);
printf("result = %d, n = %d\n", result, n);
具有未定义的行为(假设9999999999999999999999999太大而无法存储在int
中)。
你可能能够做的是找到一个开源的sscanf
实现,并修改它,使其仅验证字符串与格式是否匹配,而不存储任何内容。(处理实现的许可证留作练习。)如果你发现sscanf
风格的格式字符串特别方便解决问题,那么这是有意义的。否则,正则表达式可能是正确的方法(虽然不在C标准中,但很容易找到实现)。
man 3 regexec
。 - Dan Fego