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

时间:2017-11-19 06:50:33

标签: c string tokenize strtok

我正在尝试使用方括号[]作为分隔符来标记字符串。我可以使用一个输入准确地将字符串标记为我想要的字符串,但它有其他错误。例如,我在分隔符之前有一个带字符的字符串,它工作正常,但如果在分隔符之前没有任何内容,那么我会遇到错误。

这个给了我一个错误。 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, "]");
}

2 个答案:

答案 0 :(得分:1)

简而言之:第二次在第一个示例中调用strtok()与在空字符串中调用它相同,这就是您获得NULL的原因。< / p>

每次拨打strtok都会根据您选择的分隔符为您提供令牌。在你的第一次尝试中:

char name[] = "[name]";
char *token = strtok(name, "[");
char *token2 = strtok(NULL, "]");

您选择的分隔符为"[",因此对strtok的第一次调用将获得"name]",因为这是字符串中的第一个标记(请记住该字符串以分隔符开头) 。第二个将获得NULL,因为"name]"是原始字符串的结尾,现在调用strotk()就像在空字符串上调用它一样。

strtok()使用一个静态缓冲区来保存原始字符串,每次调用都使用&#34;该缓冲区的另一部分。第一次通话后,功能&#34;使用&#34;整个缓冲区。

在你的第二次尝试中:

char line[] = "Hello [name]";
char *tok = strtok(line, "[");
char *tok2 = strtok(NULL, "]");

你在一个字符串中调用strtok,其中间有分隔符,所以你得到一个令牌并且你仍然在该函数使用的静态缓冲区中留下一个字符串。这使得strtok()的第二次调用能够返回有效的令牌,而不是NULL

答案 1 :(得分:0)

如果您只是尝试在一对括号[...]之间提取内容,那么strchr提供了一种更直接的方式来完成任务。当您使用单分隔符(例如strtok然后'[')呼叫']'时,您实际上正在执行对strchr的两次连续调用所执行的操作字符相同'['然后']'

例如,下面将解析命令行中给出的字符串,用于括号之间的字符(如果没有给出参数,则默认为"[some name]"),最多为MAXNM个字符(包括< em> nul-terminatedating 字符):

#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那样)。因此,此方法可以安全地与字符串文字或其他常量字符串一起使用。

示例使用/输出

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

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