如何检查字符串匹配格式 "printf like - %d/..."
How to check string matches format "printf like - %d/..."
我有像 "/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
你有什么解决办法吗?
提前致谢。
这是一个相当棘手的问题。我不认为 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"
但我不确定。不过,我认为这是解决此问题的最简单方法之一。
我认为标准库中没有类似 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 == '[=10=]');
}
一些注意事项:
- 我用
strtol
解析了数字。如果你想包含 floating-point 数字格式,你可以使用 strtod
,如果你的嵌入式系统提供的话。 (您还可以将 isdigit()
个字符的延伸部分解析为有效数字。)
'u'
案例在此落入 'd'
案例。函数 strtoul
解析一个 unsigned long,但它允许一个减号,所以这种情况会被显式捕获。 (但是它被捕获的方式,它不允许前导白色space。)
- 您可以实施自己的格式或 re-interpret 现有格式。例如,您可以决定不希望数字前导白色 space 或者字符串以斜杠结尾。
最简单的就是尝试用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
格式说明符来获取已解析的字节数,并为下一次解析递增字符串。
这个例子滥用了如果解析没有达到 %n
说明符就不会修改 bytes_parsed
的事实:
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"; */
......
我有像 "/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
你有什么解决办法吗?
提前致谢。
这是一个相当棘手的问题。我不认为 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"
但我不确定。不过,我认为这是解决此问题的最简单方法之一。
我认为标准库中没有类似 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 == '[=10=]');
}
一些注意事项:
- 我用
strtol
解析了数字。如果你想包含 floating-point 数字格式,你可以使用strtod
,如果你的嵌入式系统提供的话。 (您还可以将isdigit()
个字符的延伸部分解析为有效数字。) 'u'
案例在此落入'd'
案例。函数strtoul
解析一个 unsigned long,但它允许一个减号,所以这种情况会被显式捕获。 (但是它被捕获的方式,它不允许前导白色space。)- 您可以实施自己的格式或 re-interpret 现有格式。例如,您可以决定不希望数字前导白色 space 或者字符串以斜杠结尾。
最简单的就是尝试用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
格式说明符来获取已解析的字节数,并为下一次解析递增字符串。
这个例子滥用了如果解析没有达到 %n
说明符就不会修改 bytes_parsed
的事实:
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"; */
......