为什么 strtok() 不以某种方式标记字符串?

Why does strtok() not tokenize the string a certain way?

我正在尝试使用方括号 [] 作为分隔符来标记字符串。我可以用一个输入准确地标记一个字符串,但其他时候它会出错。例如,我有一个在定界符之前有字符的字符串,它工作正常,但如果在定界符之前没有任何内容,那么我 运行 会出错。

这个给我一个错误。 token2 最终是 NULLtoken"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;
}

注意: 使用 strchrstrncpy 在固定分隔符之间配对的好处是您无需修改​​原始字符串(如 strtok 确实如此)。因此,此方法可以安全地用于 字符串文字 或其他常量字符串。

例子Use/Output

$ ./bin/brackets
name : 'some name'

$ ./bin/brackets "this [is the name] and more"
name : 'is the name'