我有"/users/5/10/fnvfnvdjvndfvjvdklchsh"
这样的动态字符串,还有"/users/%u/%d/%s"
这样的动态格式,如何检查这些字符串是否匹配?
作为字符串,我的意思是char[255]
或char* str = malloc(x)
。
我尝试使用sscanf
,但我不知道参数和类型的数量,如果我这样做:
int res = sscanf(input, format);
我有堆栈溢出,或者我可以分配堆栈来防止这种情况吗? 这样的示例:
void* buffer = malloc(1024);
int res = sscanf(input, format, buffer);
我想要这样的功能:
bool stringMatches(const char* format, const char* input);
stringMatches("/users/%u/%d/%s", "/users/5/10/fnvfnvdjvndfvjvdklchsh"); //true
stringMatches("/users/%u/%d/%s", "/users/5/10"); //false
stringMatches("/users/%u/%d/%s", "/users/-10/10/aaa"); //false %u is unsigned
您看到任何解决方案了吗?
预先感谢。
答案 0 :(得分:3)
我认为标准库中没有类似scanf
的匹配函数,因此您必须编写自己的匹配函数。复制scanf
行为的所有细节很困难,但可能没有必要。
如果只允许%
,并且只选择有限的单一格式标识符,而没有尺寸,宽度和精度信息,则代码并不复杂:
bool stringMatches(const char *format, const char *input)
{
while (*format) {
if (*format == '%') {
format++;
switch(*format++) {
case '%': {
if (*input++ != '%') return false;
}
break;
case 'u':
if (*input == '-') return false;
// continue with 'd' case
case 'd': {
char *end;
strtol(input, &end, 0);
if (end == input) return false;
input = end;
}
break;
case 's': {
if (isspace((uint8_t) *input)) return false;
while (*input && !isspace((uint8_t) *input)) input++;
}
break;
default:
return false;
}
} else {
if (*format++ != *input++) return false;
}
}
return (*input == '\0');
}
一些注意事项:
strtol
解析了数字。如果要包括浮点数格式,则在嵌入式系统提供的情况下,可以使用strtod
。 (您也可以将isdigit()
个字符的延伸部分解析为有效数字。)'u'
情况可以归结为'd'
情况。函数strtoul
解析一个无符号的long,但是它允许一个负号,因此该情况被明确捕获。 (但是,它被捕获的方式将不允许前导空格。)答案 1 :(得分:1)
这是一个相当棘手的问题。我认为C没有非常有用的内置函数会对您有所帮助。
您可以做的是使用正则表达式。像这样:
#include <sys/types.h>
#include <regex.h>
#include <stdio.h>
int main(void)
{
regex_t regex;
if (regcomp(®ex, "/users/[[:digit:]]+", 0)) {
fprintf("Error\n");
exit(1);
}
char *mystring = "/users/5/10/fnvfnvdjvndfvjvdklchsh";
if( regexec(®ex, myString, 0, NULL, 0) == 0)
printf("Match\n");
}
上面的代码中的正则表达式不适合您的示例。我只是用一些东西来展示这个想法。我认为它将与格式字符串"/users/%u"
相对应,但是我不确定。尽管如此,我认为这是解决此问题的最简单方法之一。
答案 2 :(得分:0)
最简单的方法是尝试使用sscanf
对其进行解析,然后查看扫描是否成功。
char * str = "/users/5/10/fnvfnvdjvndfvjvdklchsh";
unsigned int tmp_u;
int tmp_d;
char tmp_s[256];
int n = sscanf (str, "/users/%u/%d/%s", &tmp_u, &tmp_d, tmp_s);
if (n!=3)
{
/* Match failed */
}
请记住,您不必一劳永逸。您可以使用%n
格式说明符来获取已解析的字节数,并为下一次解析增加字符串。
此示例滥用了以下事实:如果解析未达到bytes_parsed
说明符,将不会修改%n
:
char * str = "/users/5/10/fnvfnvdjvndfvjvdklchsh";
int bytes_parsed = 0;
/* parse prefix */
sscanf("/users/%n", &bytes_parsed);
if (bytes_parsed == 0)
{
/* Parse error */
}
str += bytes_parsed; /* str = "5/10/fnvfnvdjvndfvjvdklchsh"; */
bytes_parsed = 0;
/* Parse next num */
unsigned int tmp_u
sscanf(str, "%u%n", &tmp_u, &bytes_parsed);
if (bytes_parsed)
{
/* Number was an unsigned, do something */
}
else
{
/* First number was not an `unsigned`, so we try parsing it as signed */
unsigned int tmp_d
sscanf(str, "%d%n", &tmp_d, &bytes_parsed);
if (bytes_parsed)
{
/* Number was an unsigned, do something */
}
}
if (!bytes_parsed)
{
/* failed parsing number */
}
str += bytes_parsed; /* str = "/10/fnvfnvdjvndfvjvdklchsh"; */
......