如何在C语言中将字符串分割成标记?

8
如何在C中按'&'拆分字符串为标记?

1
https://dev59.com/pXVC5IYBdhLWcg3whRgw - Laurynas Biveinis
看起来这个问题是关于分割一个字面字符串的(尽管问题缺乏细节,只说“不起作用”)。这可能是或可能不是OP想要的。我们应该给他一个机会解释一下。被分割的字符串是一个字面字符串,还是只读的? - Alok Singhal
5个回答

13

9
我会像这样做(使用 strchr()):
#include <string.h>

char *data = "this&&that&other";
char *next;
char *curr = data;
while ((next = strchr(curr, '&')) != NULL) {
    /* process curr to next-1 */
    curr = next + 1;
}
/* process the remaining string (the last token) */

strchr(const char *s, int c)函数返回指向s中下一个出现c的位置的指针,如果cs中未找到,则返回NULL

你可能可以使用strtok(),但我不喜欢strtok(),因为:

  • 它修改了被分割的字符串,因此对于字面字符串来说不起作用,或者在你想要保留字符串以供其他目的时不是很有用。在这种情况下,你必须先将字符串复制到临时变量中。
  • 它合并相邻的分隔符,所以如果你的字符串是"a&&b&c",返回的标记是"a""b""c"。请注意,在"a"之后没有空标记。
  • 它不是线程安全的。

我想这也取决于C语言的实现。在我的系统上,当我调用strtok()时,字符串本身并没有被修改。实际上,我甚至不知道它怎么可能会被修改。毕竟,它只需要在字符串中产生指向不同标记开头的指针。 - Cees Meijer
Cees Meijer:strtok()确实修改了参数字符串 - 分隔符字符被替换为'\0',以便返回的字符串得到正确的终止。 - caf
1
如果要符合标准,strtok必须修改字符串。根据C标准:如果找到这样的字符,则将其覆盖为空字符,从而终止当前令牌。这非常明确。http://opengroup.org/onlinepubs/009695399/functions/strtok.html。你能发一下`strtok()`不修改字符串的代码吗? - Alok Singhal
哎呀,我想你一定是对的。我的错误。确实,将分隔符更改为\0是它能够工作的唯一方式。经过对我的代码进行更仔细的检查(它是一个嵌入式系统,因此检查反汇编代码并不那么困难),我看到这正是发生的事情。 - Cees Meijer
我不明白这将如何通过 & 拆分字符串。例如,你怎么能单独获取第一个标记 this - nikk wong

3
您可以使用如下示例中所示的strok()函数。
/// Function to parse a string in separate tokens 

int parse_string(char pInputString[MAX_STRING_LENGTH],char *Delimiter,
                   char *pToken[MAX_TOKENS])
{
  int i;
  i = 0;

  pToken[i] = strtok(pInputString, Delimiter);
  i++;

  while ((pToken[i] = strtok(NULL, Delimiter)) != NULL){
     i++;
  }
  return i;
}

/// The array pTokens[] now contains the pointers to the start of each token in the (unchanged) original string.

sprintf(String,"Token1&Token2");
NrOfParameters = parse_string(String,"&",pTokens);

sprintf("%s, %s",pToken[0],pToken[1]);

0
对我来说,使用strtok()函数不直观且过于复杂,因此我设法自己创建了一个函数。它接受一个要分割的字符串作为参数,还有一个用于确定标记之间空格的字符和表示找到的标记数量的指针(在循环中打印这些标记时非常有用)。该函数的一个缺点是每个标记的最大长度是固定的。
#include <stdlib.h>
#include <string.h>
#define MAX_WORD_LEN 32


char **txtspt(const char *text, char split_char, int *w_count)
{
    if(strlen(text) <= 1) 
        return NULL;

    char **cpy0 = NULL;
    int i, j = 0, k = 0, words = 1;

    //Words counting
    for(i = 0; i < strlen(text); ++i)
    {
        if(text[i] == split_char && text[i + 1] != '\0')
        {
            ++words;
        }
    }
    //Memory reservation
    cpy0 = (char **) malloc(strlen(text) * words);
    for(i = 0; i < words; ++i)
    {
        cpy0[i] = (char *) malloc(MAX_WORD_LEN);
    }

    //Splitting
    for(i = 0; i < strlen(text) + 1; ++i)
    {
       if(text[i] == split_char)
       {
           cpy0[k++][j] = '\0';
           j = 0;
       }
       else
       {
           if(text[i] != '\n')           //Helpful, when using fgets() 
                cpy0[k][j++] = text[i];  //function
       }

    }

    *w_count = words;
    return cpy0;
}

0
很简单:
char str[] = "&a&&b&c"; // a mutable string

for (char *cp = str; (cp = strtok(cp, "&")) != NULL; cp = NULL) {
    /* do something with the token */
}

这里只有一个对 strtok() 的调用,一个分隔符字符串的实例,而且 cp 的作用域仅限于这个循环内。

建议使用 strchr() 并没有考虑到多个分隔符字符。如果建议使用 strcspn() 可能会更好。而且请注意,最后一个标记必须在循环结束后处理。设计不太好...

strtok() 的一个优点是标记已经被隔离在它们当前的位置。如果它们的地址被保存在一个指针数组中,它们可以被重复使用,而不需要一遍又一遍地隔离它们。


无论&a&&b&c是否应该像strtok()(或更好的strtok_r())一样分成3部分,或者像strchr()一样分成5部分,包括2个空字符串,这取决于规范的问题。对于这个问题,问题本身相当模糊:其他语言中可用的split方法更倾向于后者,而tokens则更倾向于前者。不过,OP现在肯定比12年前更了解情况了。使用具有相同特性的strtok_r的替代方法似乎更可取,尽管它不是标准的。 - undefined
@chqrlie 你的观点,“3或5个令牌”,是有道理的,而且原帖没有具体说明... 这里的strchr()答案有一些问题。而且,“double strtok()”答案也有它自己的问题(如果你明白我的意思的话 :-)... 看到这个问题,我想提供我更喜欢的版本... 不幸的是,我没有strtok_r()... 也许这是个周末的项目!!:-)` - undefined
char *strtok_r(char *s, const char *delim, char **context) { char *token = NULL; if (s == NULL) s = *context; /* 跳过初始的分隔符 */ s += strspn(s, delim); if (*s != '\0') { /* 我们有一个标记 */ token = s; /* 跳过标记 */ s += strcspn(s, delim); if (*s != '\0') { /* 切断字符串以终止标记 */ *s++ = '\0'; } } *context = s; return token; }``` - undefined
1
@chqrlie 好的!谢谢...看来我得去洗车了...非常感谢!:-) - undefined
1
或者来巴黎,喝一杯葡萄酒吧 :) - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接