为什么 strtok() 不以某种方式标记字符串?
Why does strtok() not tokenize the string a certain way?
我正在尝试使用方括号 [] 作为分隔符来标记字符串。我可以用一个输入准确地标记一个字符串,但其他时候它会出错。例如,我有一个在定界符之前有字符的字符串,它工作正常,但如果在定界符之前没有任何内容,那么我 运行 会出错。
这个给我一个错误。 token2
最终是 NULL
,token
是 "name]"
,括号还在。
char name[] = "[name]";
char *token = strtok(name, "[");
char *token2 = strtok(NULL, "]");
输出:
token = name]
token2 = NULL
但是,如果我有以下内容,那么它就可以正常工作。
char line[] = "Hello [name]";
char *tok = strtok(line, "[");
char *tok2 = strtok(NULL, "]");
输出:
tok = Hello
tok2 = name
当输入只是类似于 "[name]"
时,我不明白我做错了什么。我只想要括号内的内容。
编辑:
感谢大家的意见和建议。我找到了解决我正在尝试做的事情的方法。根据@Ryan 和@StoryTeller 的建议,我首先检查输入是否以 [
开头并以 []
分隔。这是我为输入尝试和工作的内容:
char name[] = "[name]", *token = NULL, *token2 = NULL;
if (name[0] == '[')
{
token = strtok(name, "[]");
}
else
{
token = strtok(name, "[");
token2 = strtok(NULL, "]");
}
简而言之:您在第一个示例中第二次调用 strtok()
与在空字符串上调用它相同,这就是为什么您得到 NULL
.
每次调用 strtok
都会根据您选择的分隔符为您提供令牌。在您的第一次尝试中:
char name[] = "[name]";
char *token = strtok(name, "[");
char *token2 = strtok(NULL, "]");
您选择的分隔符是 "["
因此第一次调用 strtok
将得到 "name]"
,因为这是字符串中的第一个标记(请记住字符串以分隔符)。第二个将得到 NULL,因为 "name]"
是原始字符串的末尾,现在调用 strotk()
就像在空字符串上调用它一样。
strtok()
使用静态缓冲区保存原始字符串,每次调用 "uses" 该缓冲区的另一部分。第一次调用后,函数 "used" 整个缓冲区。
第二次尝试:
char line[] = "Hello [name]";
char *tok = strtok(line, "[");
char *tok2 = strtok(NULL, "]");
您在中间带有定界符的字符串上调用 strtok
,因此您得到了一个标记,并且函数使用的静态缓冲区中仍有一个字符串。这使得 strtok()
的第二次调用成为 return 一个有效的令牌而不是 NULL
.
如果您只是想提取一对括号 [...]
之间的内容,那么 strchr
提供了一种更直接的方法来完成任务。当您使用单定界符调用 strtok
时(例如 '['
然后 ']'
),您实际上是在做与两次连续调用 strchr
相同的操作字符相同 '['
然后 ']'
。
例如,下面将解析命令行上给出的字符串以获取括号之间的字符(如果没有给出参数,则默认为 "[some name]"
),最多为 MAXNM
个字符(包括nul-terminating 字符):
#include <stdio.h>
#include <string.h>
#define MAXNM 128
int main (int argc, char **argv) {
char *s = argc > 1 ? argv[1] : "[some name]", /* input */
*p = s, /* pointer */
*ep, /* end pointer */
buf[MAXNM] = ""; /* buffer for result */
/* if starting and ending bracket are present in input */
if ((p = strchr (s, '[')) && (ep = strchr (p, ']'))) {
if (ep - p > MAXNM) { /* length + 1 > MAXNM ? */
fprintf (stderr, "error: result too long.\n");
return 1;
}
/* copy betweeen brackets to buf (+1 for char after `[`) */
strncpy (buf, p + 1, ep - p - 1); /* ep - p - 1 for length */
buf[ep - p - 1] = 0; /* nul terminate, also done via initialization */
printf ("name : '%s'\n", buf); /* output the name */
}
else
fprintf (stderr, "error: no enclosing brackets found in input.\n");
return 0;
}
注意: 使用 strchr
和 strncpy
在固定分隔符之间配对的好处是您无需修改原始字符串(如 strtok
确实如此)。因此,此方法可以安全地用于 字符串文字 或其他常量字符串。
例子Use/Output
$ ./bin/brackets
name : 'some name'
$ ./bin/brackets "this [is the name] and more"
name : 'is the name'
我正在尝试使用方括号 [] 作为分隔符来标记字符串。我可以用一个输入准确地标记一个字符串,但其他时候它会出错。例如,我有一个在定界符之前有字符的字符串,它工作正常,但如果在定界符之前没有任何内容,那么我 运行 会出错。
这个给我一个错误。 token2
最终是 NULL
,token
是 "name]"
,括号还在。
char name[] = "[name]";
char *token = strtok(name, "[");
char *token2 = strtok(NULL, "]");
输出:
token = name]
token2 = NULL
但是,如果我有以下内容,那么它就可以正常工作。
char line[] = "Hello [name]";
char *tok = strtok(line, "[");
char *tok2 = strtok(NULL, "]");
输出:
tok = Hello
tok2 = name
当输入只是类似于 "[name]"
时,我不明白我做错了什么。我只想要括号内的内容。
编辑:
感谢大家的意见和建议。我找到了解决我正在尝试做的事情的方法。根据@Ryan 和@StoryTeller 的建议,我首先检查输入是否以 [
开头并以 []
分隔。这是我为输入尝试和工作的内容:
char name[] = "[name]", *token = NULL, *token2 = NULL;
if (name[0] == '[')
{
token = strtok(name, "[]");
}
else
{
token = strtok(name, "[");
token2 = strtok(NULL, "]");
}
简而言之:您在第一个示例中第二次调用 strtok()
与在空字符串上调用它相同,这就是为什么您得到 NULL
.
每次调用 strtok
都会根据您选择的分隔符为您提供令牌。在您的第一次尝试中:
char name[] = "[name]";
char *token = strtok(name, "[");
char *token2 = strtok(NULL, "]");
您选择的分隔符是 "["
因此第一次调用 strtok
将得到 "name]"
,因为这是字符串中的第一个标记(请记住字符串以分隔符)。第二个将得到 NULL,因为 "name]"
是原始字符串的末尾,现在调用 strotk()
就像在空字符串上调用它一样。
strtok()
使用静态缓冲区保存原始字符串,每次调用 "uses" 该缓冲区的另一部分。第一次调用后,函数 "used" 整个缓冲区。
第二次尝试:
char line[] = "Hello [name]";
char *tok = strtok(line, "[");
char *tok2 = strtok(NULL, "]");
您在中间带有定界符的字符串上调用 strtok
,因此您得到了一个标记,并且函数使用的静态缓冲区中仍有一个字符串。这使得 strtok()
的第二次调用成为 return 一个有效的令牌而不是 NULL
.
如果您只是想提取一对括号 [...]
之间的内容,那么 strchr
提供了一种更直接的方法来完成任务。当您使用单定界符调用 strtok
时(例如 '['
然后 ']'
),您实际上是在做与两次连续调用 strchr
相同的操作字符相同 '['
然后 ']'
。
例如,下面将解析命令行上给出的字符串以获取括号之间的字符(如果没有给出参数,则默认为 "[some name]"
),最多为 MAXNM
个字符(包括nul-terminating 字符):
#include <stdio.h>
#include <string.h>
#define MAXNM 128
int main (int argc, char **argv) {
char *s = argc > 1 ? argv[1] : "[some name]", /* input */
*p = s, /* pointer */
*ep, /* end pointer */
buf[MAXNM] = ""; /* buffer for result */
/* if starting and ending bracket are present in input */
if ((p = strchr (s, '[')) && (ep = strchr (p, ']'))) {
if (ep - p > MAXNM) { /* length + 1 > MAXNM ? */
fprintf (stderr, "error: result too long.\n");
return 1;
}
/* copy betweeen brackets to buf (+1 for char after `[`) */
strncpy (buf, p + 1, ep - p - 1); /* ep - p - 1 for length */
buf[ep - p - 1] = 0; /* nul terminate, also done via initialization */
printf ("name : '%s'\n", buf); /* output the name */
}
else
fprintf (stderr, "error: no enclosing brackets found in input.\n");
return 0;
}
注意: 使用 strchr
和 strncpy
在固定分隔符之间配对的好处是您无需修改原始字符串(如 strtok
确实如此)。因此,此方法可以安全地用于 字符串文字 或其他常量字符串。
例子Use/Output
$ ./bin/brackets
name : 'some name'
$ ./bin/brackets "this [is the name] and more"
name : 'is the name'