我想知道C程序员通常如何从字符串中提取数据?我读了很多关于strtok
的内容,但我个人不喜欢这个函数的工作方式。用NULL
作为参数再次调用它对我来说似乎很奇怪。我曾经偶然发现这段代码,我发现它很漂亮:
sscanf(data, "%*[^=]%*c%[^&]%*[^=]%*c%[^&]", usr, pw);
这将从URL查询字符串中提取数据(仅var1=value&var2=value
)。
是否有理由使用strtok
而不是sscanf
?表现可能吗?
答案 0 :(得分:2)
恕我直言,最佳方式是最具可读性和可理解性的方式。 sscanf
和strtok
完全取消了从网址中提取用户/ pw的资格。
相反,使用strchr
和strrchr
查找您要查找的字符串的边界(在URL中为斜线,at符号,冒号,有什么),然后是memcpy从开始到结束到您需要数据和NUL的地方。如果字符串具有意外的格式,这也允许适当的错误处理。
答案 1 :(得分:1)
sscanf
使用非常不完整(虽然有效实现)正则表达式语法,因此如果您想要做一些更复杂的事情, 使用sscanf
。
话虽如此,strtok
并不是重新进入的,所以如果你使用线程,那么你运气不好。
但总的来说,对于特定环境而言更快跑步并且更优雅的那种通常被认为是那种环境中最惯用的。
答案 2 :(得分:1)
strtok
是一个更简单的低级函数,主要用于标记具有未知元素数的字符串。
NULL
用于告诉strtok继续从最后一个位置扫描字符串,保存一些指针操作,并可能(内部执行)初始化。
还有可读性问题。查看代码片段,需要一些时间来了解正在发生的事情。
答案 3 :(得分:1)
在某些任务中,它们都更好或更方便:
sscanf
允许您简明地指定一个相当复杂的模板,用于解析一行文本中的值,但这是非常不可原谅的。如果输入文本甚至与模板中的字符不同,则扫描将失败。因此,例如,它几乎不是用于人类生成输入的正确工具。它对于扫描自动生成的输出非常有用,例如服务器日志行。
strtok
更灵活,但也更冗长:只用几个字段解析一行可能需要多行代码。它也具有破坏性:它实际上修改了传递给它的字符串,因此您可能需要在调用strtok
之前复制数据。
答案 4 :(得分:0)
我自己创建了一个小的头文件,其中包含一些可以帮助的函数定义,例如char **Split(src, sep)
函数和int DoubleArrLen(char **arr)
,
如果你能以任何方式改进它,那么这是一个小小的1小时工作。
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
char *substring(char *string, int position, int length)
{
char *pointer;
int c;
pointer = malloc(length+1);
if (pointer == NULL)
{
printf("Unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
for (c = 0 ; c < position -1 ; c++)
string++;
for (c = 0 ; c < length ; c++)
{
*(pointer+c) = *string;
string++;
}
*(pointer+c) = '\0';
return pointer;
}
char **Split(char *a_str, const char a_delim)
{
char **result = 0;
size_t count = 0;
char *tmp = a_str;
char *last_comma = 0;
/* Count how many elements will be extracted. */
while (*tmp)
{
if (a_delim == *tmp)
{
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = malloc(sizeof(char *) * count);
if (result)
{
char delim[2] = { a_delim, '\0' }; // Fix for inconsistent splitting
size_t idx = 0;
char *token = strtok(a_str, delim);
while (token)
{
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, delim);
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
static int SplitLen(char **array)
{
int i = 0;
while (*array++ != 0)
i++;
return i;
}
int IndexOf(char *str, char *ch)
{
int i;
int cnt;
int result = -1;
if(strlen(str) >= strlen(ch))
{
for(i = 0; i<strlen(str); i++)
{
if(str[i] == ch[0])
{
result = i;
for(cnt = 1; cnt < strlen(ch); cnt++)
{
if(str[i + cnt] != ch[cnt]) result = -1; break;
}
}
}
}
return result;
}
int IndexOfChar(char *str, char ch)
{
int result = -1;
int i = 0;
for(;i<strlen(str); i++)
{
if(str[i] == ch)
{
result = i;
break;
}
}
return result;
}
一点点解释可以是功能: substring函数提取字符串的一部分。 IndexOf()函数在源字符串中搜索字符串。 其他人应该是不言自明的。 这包括我之前指出的Split函数,你可以使用它而不是strtok ..