在我的程序中,我使用sscanf
来检查字符串是否为给定格式。为此,我提供格式字符串中的参数数量,并在解析输入时检查sscanf
是否返回相同的数字。
作为原始解析器的一部分,我想检查字符串是否与多种格式之一匹配。 sscanf
函数是可变参数,那么如何处理需要传递的不同数量的参数?
目前,我只是将大量的参数(例如50)传递给函数,并希望格式字符串不包含更多参数。
有没有更好的方法呢?
答案 0 :(得分:3)
你真的需要比scanf
重的东西。您必须告诉 scanf
您的输入是什么格式;它本身无法解决任何问题。
如果您有权访问POSIX,请查看regex.h
它可能是您需要的一切。
否则,你就会陷入困境。如果格式相当复杂,lex
和yacc
会很好,但除此之外,strtok
或(getchar
+ switch
}可能是最佳选择。
修改强> 既然你可以使用POSIX,这里有一个简单的例子,介绍如何从c中的正则表达式中提取数据。 (为简洁起见,排除了错误检查。)
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
答案 1 :(得分:0)
你应该使用lex / yacc来构建一个合适的解析器。或者,首先使用strtok
对字符串进行标记可能会简化您的问题。 (注意:正确使用strtok
非常棘手 - 请仔细阅读其文档。)
答案 2 :(得分:0)
我不确定它是否回答了你的问题,但you use varargs
in C允许函数的变量数量可变。
void myscanf(const char *fmt, ...)
{
}
答案 3 :(得分:0)
无益的答案是“不要这样做,正确编写解析器,可能使用lex
和/或yacc
或bison
”。
你问的问题的答案是“是的,你可以做到”。我不相信有任何理由可以存在更多可变参数,而不是格式要求,尽管很少会是一件坏事。我假设你有一个数组或可能的格式列表,你在循环中调用sscanf。
答案 4 :(得分:0)
您可以使用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);
}
希望这有帮助!
答案 5 :(得分:0)
如果您在编写代码时不知道 参数的数量和类型,sscanf()
无法安全地执行您要执行的操作。
将50个参数传递给sscanf()
是正常的(格式字符串不会消耗的参数会被计算,但会被忽略),但是与格式字符串相对应的参数必须是促销之后的预期类型;否则,行为未定义。因此,如果您想要检测是否可以使用"%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标准中,但是很容易找到实现)。