首页 > 编程知识 正文

用strtok函数将字符串,c语言中分割字符串

时间:2023-05-03 19:09:23 阅读:241759 作者:32

  在c/c++中,字符串分割函数主要有两种:一是strtok函数,另一个就是strsep函数。下面我们对这两个函数作一个详细解释说明。

1、strtok 原形:

  char* strtok(char *str, const char *delim);

功能:

  分解字符串为一组字符串;str为要分割的字符串,delim为分隔符;

返回值:

   从str开头开始的一个个子串,当没有分割的子串时返回NULL。

说明:

  * strtok函数工作时,若在字符串中发现分隔符会将该字符改为’’;
  * 第一次调用时,strtok函数必须给予参数str字符串,之后调用则将str参数设置为NULL;至于为什么之后调用将str参数设置为NULL,在下文介绍;
  * strtok内部记录上次调用字符串的位置,所以不支持多线程,可重入版本为strtok_r。

示例 #include <stdio.h>#include <string.h>int main(){ char str[] = "hello,,world!#c";//strtok函数会改变源字符串,所以不能写 char* str = ""; char* delim = ",#"; char *token = NULL; token = strtok(str,delim); while(token) { puts(token); token = strtok(NULL,delim); } return 0;}

运行结果:

源码

  其源码有多种实现方式,下面只简单介绍其中的一种。

//字符串分割函数#include<stdio.h>#include<stdlib.h>#include<string.h>#include<assert.h>char* strtok(char* str,const char* delim);int main(){ char str[] = "hello#world#c"; char* delim = "#"; char* ret = strtok(str,delim); while(ret) { puts(ret); ret = strtok(NULL,delim); } return 0;}char* strtok(char* str,const char* delim){ static char* last = NULL; register int ch; if(str == 0) { str = last; } do { if((ch = *str++) == '') { return 0; } }while(strchr(delim,ch)); --str; last = str + strcspn(str,delim); if(*last) { *last++ = 0; } return str;}

说明:
  * strcspn函数,其返回值为n,表示字符串的前n个字符均未出现分隔符delim;
 看了源码实现,就能明白为什么第二次传参传的时NULL了?
 因为若是传NULL,表示是第二次调用此函数,就将上次的last状态赋给str,然后跳过分隔符,通过strcspn截取需要的字符串,此时last指向下一个分隔符或字符串结尾’’处,通过判断last是否为空,若非空,表示last此时指向分隔符,然后将分隔符置为0,即截断字符串,last然后指向下一个字符。最后返回str,重复此过程,直到字符串末尾。

2、strsep 原形:

  char* strtsep(char* * str, const char *delim);

功能:

  分解字符串为一组字符串;str为要分割的字符串,delim为分隔符;

返回值:

   被delim分开的左边的那个字符串,同时会导致str的值会指向分隔符号右边的字符串的起始位置

示例 #include<stdio.h>#include<string.h>int main(){ char s[] = "hell##hhh#www"; char* delim = "#"; char* ret = NULL; char* str = strdup(s); ret = strsep(&str,delim); while(ret) { puts(ret); ret = strsep(&str,delim); } return 0;}

运行结果

  此时,有没有发现一个问题,为什么在strtok中没有多余换行,而在strsep中却有?
  这是因为若被分割的字符串有连续的多个分割符出现,strtok会返回NULL,而strsep会返回空串,所以会将其当作分割下来的字符串而打印出来。
  因此,我们若想用strsep分割字符串,必须进行返回值是否为空的检验。

改进代码:

#include<stdio.h>#include<string.h>int main(){ char s[] = "hell##hhh#www"; char* delim = "#"; char* ret = NULL; char* str = strdup(s); ret = strsep(&str,delim); while(ret) { if(*ret) //返回值检验 { puts(ret); } ret = strsep(&str,delim); } return 0;}

运行结果:

源码 #include<stdio.h>#include<string.h>char *my_strsep(char **str, const char *delim);int main(){ char str[] = "he#llo#wor##ld*asd*jji*9"; char* delim = "*#"; char* s = strdup(str); char* ret = my_strsep(&s,delim); while(ret) { if(*ret)//排除连续出现分隔符时多打印空格 { puts(ret); } ret = my_strsep(&s,delim); } return 0;}char *my_strsep(char **str, const char *delim){ char *begin = NULL; char *end = NULL; begin = *str; if(begin == NULL) { return NULL; } //delim分隔符是单个字符,调用strchr if(delim[0] == '' || delim[1] == '') { char ch = delim[0]; if(ch == '') { end = NULL; } else { if(*begin == ch) { end = begin; } else if(*begin == '') { end = NULL; } else { end = strchr(begin + 1, ch); } } } else { end = strpbrk(begin, delim); //delim有两个字符以上,调用strpbrk } if(end) { *end++ = ''; *str = end; } else { *str = NULL; } return begin;} 总结

  1、strtok是不可重入的(strtok_r是strtok的可重入版本),strseq是可重入的。
  2.strsep和strtok都对修改了src字符串。所以不能使用字符串常量作为分割字符串。 

例如:char* str = "he*#llo*wo";char* delim = "*#"char* ret = strtok(str,delim); #错误,str为常量,不可更改

  3.strsep和strtok对字符串分割结果不一致。若被分割的字符串有连续的多个分割符出现,strtok会返回NULL,而strsep会返回空串;因此,我们若想用strsep分割字符串,必须进行返回值是否为空的检验。
  4、最好使用strsep;尽量避免使用strtok。

下面的说明摘自于最新的Linux内核2.6.29,说明了strtok()已经不再使用,由速度更快的strsep()代替。/** linux/lib/string.c** Copyright (C) 1991, 1992 Linus Torvalds*/  /** stupid library routines.. The optimized versions should generally be found  * as inline code in <asm-xx/string.h>  * These are buggy as well..  * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>  * - Added strsep() which will replace strtok() soon (because strsep() is  * reentrant and should be faster). Use only strsep() in new code, please.  ** * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,  * Matthew Hawkins <matt@mh.dropbear.id.au>  * - Kissed strtok() goodbye*/

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。