有两个问题strtok()
。
- 它修改其输入字符串。
- 一次只能激活一组
strtok()
呼叫。
我认为你的问题是后者。您在代码中还有一个缩进问题:
if (scanf(" %[^\n]", line) > 0)
token = strtok( line, ";" );
do
{
line2 = token;
temporaryToken = strtok(line2, " ");
do
{
//divide the line2 by spaces into command and args, not the question here]
temporaryToken = strtok(NULL, " ");
} while (temporaryToken != NULL);
token = strtok( NULL, ";" );
} while(token != NULL);
您可能打算将其阅读为:
if (scanf(" %[^\n]", line) > 0)
{
token = strtok(line, ";");
do
{
line2 = token;
temporaryToken = strtok(line2, " ");
do
{
//divide the line2 by spaces into command and args, not the question here]
temporaryToken = strtok(NULL, " ");
} while (temporaryToken != NULL);
token = strtok(NULL, ";");
} while (token != NULL);
}
假设这是您想要的,您仍然会遇到一个问题,即有一个strtok()
正在运行line
,然后另一个正在运行line2
。问题是,循环line2
完全破坏了line
. 您不能将嵌套循环与strtok()
.
如果您必须使用类似的东西strtok()
,那么寻找 POSIXstrtok_r()
或 Microsoft 的strtok_s()
(但请注意,C11 标准附件 K 版本strtok_s()
是不同的 - 请参阅您使用 TR 24731 '安全' 功能吗?)。
if (scanf(" %[^\n]", line) > 0)
{
char *end1;
token = strtok_r(line, ";", &end1);
do
{
char *end2;
line2 = token;
temporaryToken = strtok_r(line2, " ", &end2);
do
{
//divide the line2 by spaces into command and args, not the question here]
temporaryToken = strtok_r(NULL, " ", &end2);
} while (temporaryToken != NULL);
token = strtok_r(NULL, ";", &end1);
} while (token != NULL);
}
关于评论
当您使用strtok()
或其亲属之一时,输入字符串将被修改,如果您有多个分隔符,您将无法判断存在哪个分隔符。您可以使用字符串的副本,并进行比较(通常基于字符串开头的偏移量)。
在使用范围内strtok_r()
,上述解决方案“有效”。这是一个测试程序来演示:
#include <stdio.h>
#include <string.h>
int main(void)
{
char line[1024];
if (scanf(" %[^\n]", line) > 0)
{
char *end1;
char *token;
printf("Input: <<%s>>\n", line);
token = strtok_r(line, ";", &end1);
do
{
char *end2;
char *line2 = token;
char *temporaryToken;
printf("Token1: <<%s>>\n", token);
temporaryToken = strtok_r(line2, " ", &end2);
do
{
printf("Token2: <<%s>>\n", temporaryToken);
//divide the line2 by spaces into command and args, not the question here]
temporaryToken = strtok_r(NULL, " ", &end2);
} while (temporaryToken != NULL);
token = strtok_r(NULL, ";", &end1);
} while (token != NULL);
}
return 0;
}
示例输入和输出:
$ ./strtok-demo
ls -la; mkdir lololol; ls -la
Input: <<ls -la; mkdir lololol; ls -la>>
Token1: <<ls -la>>
Token2: <<ls>>
Token2: <<-la>>
Token1: << mkdir lololol>>
Token2: <<mkdir>>
Token2: <<lololol>>
Token1: << ls -la>>
Token2: <<ls>>
Token2: <<-la>>
$
替代使用strcspn()
和strspn()
如果不想拆掉原来的字符串,就必须使用strtok()
族以外的其他功能。功能strcspn()
和strspn()
适用性;它们是标准 C(C89 和更高版本)的一部分,尽管比其他一些函数鲜为人知。但他们很适合这项任务。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char *substrdup(const char *src, size_t len);
int main(void)
{
char line[1024];
if (scanf(" %[^\n]", line) > 0)
{
char *start1 = line;
size_t len1;
printf("Input: <<%s>>\n", line);
while ((len1 = strcspn(start1, ";")) != 0)
{
char *copy = substrdup(start1, len1);
char *start2 = copy;
size_t len2;
printf("Token1: %zd <<%.*s>>\n", len1, (int)len1, start1);
printf("Copy: <<%s>>\n", copy);
start2 += strspn(start2, " "); // Skip leading white space
while ((len2 = strcspn(start2, " ")) != 0)
{
printf("Token2: %zd <<%.*s>>\n", len2, (int)len2, start2);
start2 += len2;
start2 += strspn(start2, " ");
}
free(copy);
start1 += len1;
start1 += strspn(start1, ";");
}
printf("Check: <<%s>>\n", line);
}
return 0;
}
#include <assert.h>
static char *substrdup(const char *src, size_t len)
{
char *copy = malloc(len+1);
assert(copy != 0); // Apalling error handling strategy
memmove(copy, src, len);
copy[len] = '\0';
return(copy);
}
示例输入和输出:
$ strcspn-demo
ls -la; mkdir lololol; ls -la
Input: <<ls -la; mkdir lololol; ls -la>>
Token1: 140734970342872 <<>>
Copy: <<ls -la>>
Token2: 2 <<ls>>
Token2: 3 <<-la>>
Copy: << mkdir lololol>>
Token2: 5 <<mkdir>>
Token2: 7 <<lololol>>
Copy: << ls -la>>
Token2: 2 <<ls>>
Token2: 3 <<-la>>
Check: <<ls -la; mkdir lololol; ls -la>>
$
这段代码回到了更舒适的while
循环,而不是需要使用do-while
循环,这是一个好处。