繁体   English   中英

sscanf - 不同数量的格式参数?

[英]sscanf - varying number of format arguments?

在我的程序中,我使用sscanf检查字符串是否为给定格式。 为此,我提供格式字符串中的参数数量,并检查sscanf在解析输入时是否返回相同的数字。

作为原始解析器的一部分,我想检查一个字符串是否匹配多种格式之一。 sscanf函数是可变参数,那么如何处理我需要传递的不同数量的参数?

目前,我只是将大量的参数(例如50)传递给函数,并希望格式字符串不包含更多参数。

有没有更好的方法来做到这一点?

你真的需要比scanf更重的东西。 您必须告诉 scanf您的输入是什么格式; 它本身无法解决任何问题。

如果您可以访问POSIX,请查看regex.h它可能是您需要的一切。

否则,你就会陷入困境。 如果格式相当复杂, lexyacc很好,但是否则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(&reg, "3433\\([0-5]*\\).*", 0); //replace 0 with REG_EXTENDED if desired
regexec(&reg, txt, MAX_REFS, refs, 0);
regfree(&reg);

txt[refs[0].rm_eo+1] = '\0';
int n = atoi(txt+refs[0].rm_so);
printf("%d\n", n);

打印

41235

你应该使用lex / yacc来构建一个合适的解析器。 或者,首先用strtok标记字符串可能会简化您的问题。 (注意:正确使用strtok非常棘手 - 请仔细阅读其文档。)

我不确定它是否回答了你的问题,但你在C中使用varargs来允许函数的可变数量的参数。

void myscanf(const char *fmt, ...)
{
}

无益的答案是“不要这样做,正确编写解析器,可能使用lex和/或yaccbison ”。

你问的问题的答案是“是的,你可以做到”。 我不相信有任何理由为什么没有比格式要求更多的可变参数,尽管很少会是一件坏事。 我假设你有一个数组或列表可能的格式,你在循环中调用sscanf。

您可以使用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);
}

希望这可以帮助!

如果您不知道何时编写参数的数量和类型, 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标准中,但是很容易找到实现)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM