C语言 要包含分隔符“”的函数拆分:“

j9per5c4  于 2022-12-17  发布在  其他
关注(0)|答案(1)|浏览(133)

我有一个函数,它返回一个用delim分隔的字符串数组,每次调用strtok都返回两个分隔符之间的字符串,但不包括分隔符,我希望它只返回字符串末尾为delim的字符串,如果char==':',例如,对于" ici: papa mama",如果我用delim== " \t\n:"调用它,我希望它返回一个数组,其中包含:

ici:
papa
mama

(the':'将包括在ici中,但不包括空格或制表符)。需要帮助吗

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char ** split(const char * str, const char * delim)
{
  /* count words */
  char * s = strdup(str);
  char* inter=malloc(sizeof(char)*100);// pour l etiquette ne pas oublier de mettre deux points a la fin avant de la mettre dans le

  if (strtok(s, delim) == 0){
    /* no word */
    return NULL;}

  int nw = 1;

  while (strtok(NULL, delim) != 0)
    nw += 1;

  strcpy(s, str); /* restore initial string modified by strtok */

  /* split */
  char ** v = malloc((nw + 1) * sizeof(char *));
  int i;

  v[0] = strdup(strtok(s, delim));

  for (i = 1; i != nw; ++i)
    v[i] = strdup(strtok(NULL, delim));

  v[i] = NULL; /* end mark */

  free(s);

  return v;
}

int main() {

char **words=split("ici: haha papa", " \t\n:");
printf("%s \n",words[0]);// with the two points
printf("%s \n",words[1]);// without the spaces 
printf("%s \n",words[2]);// without the spaces

return 0;
oknrviil

oknrviil1#

对于 generalized 解决方案,保留单个分隔符/定界符的唯一方法是编写您自己的标记器。
但是,在***您的特定情况***中,冒号':'似乎只出现在第一个标记的末尾。strtok()使这类问题变得特别容易,因为您可以在每次调用时更改分隔符/定界符列表。

char * first = strtok( s, " \t\n\r" );  // first token ends with whitespace

对于剩余的标记,在循环中获取它们,并将冒号包含在分隔符/定界符列表中。

char * tok = strtok( NULL, ": \t\n\r" );
根据您添加的备注:

对于第一个冒号之前可能有多个空格分隔的单词的情况(或者,根据您的注解,冒号没有相邻的空格),您必须使用strchr()(或其他搜索函数)来查找令牌,并将字符串的两部分分别送入单独的令牌化循环。

错误处理

记住在设计代码时要仔细阅读文档。C语言让你看起来可以把东西很好地链接在一起,但很多时候你不能(没有额外的帮助函数)。例如,strtok()可能返回NULL,这不是strdup()的有效输入(导致UB)。
换句话说,确保使用函数调用的返回值检查错误条件。

更换结构

回到第一个想法,strtok()很可能是用strspn()strcspn()函数实现的,而不是用strtok(),而是用这些函数,再用strndup()得到想要的子串。

更新

我觉得很无聊,所以...这里有一个通用的标记器,它 * 可能 * 做一些你想要的事情...

#include <iso646.h>
#include <stdlib.h>
#include <string.h>

char * tok2( const char ** s, const char * ks, const char * ds )
{
  // s may not be NULL
  // *s may be NULL
  if (!*s) return NULL;

  // skip any leading ds
  const char * first = *s += strspn( *s, ds );
  if (!*first) return NULL;
  
  // find the first ks|ds
  while (**s and !strchr( ks, **s ) and !strchr( ds, **s )) *s += 1;
  
  // skip any ks
  *s += strspn( *s, ks );
  
  // return substring from first (inclusive) to *s (exclusive)
  size_t n = *s - first;
  if (!n) return NULL;
    
  char * result = malloc( n+1 );
  if (!result) return NULL;
  
  result[n] = '\0';
  return strncpy( result, first, n );
}

它用MSVC和Clang干净地编译。在Windows上不要忘记添加
-D_CRT_SECURE_NO_WARNINGS到您的命令行选项,以沉默的愚蠢。
下面是我为它使用的非常简单的测试(只需将其连接到上面的代码并进行编译):

#include <stdio.h>

int main(void)
{
  const char * test_string = " one two: three four:five six : seven eight :nine ten ";
  
  printf( "given: \"%s\"\n", test_string );
  
  const char ** src = &test_string;
  char * str;
  while ((str = tok2( src, ":", " \t\r\n" )))
  {
    printf( "  \"%s\"\n", str );
    free( str );
  }
}

相关问题