在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<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,重复此过程,直到字符串末尾。
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;}运行结果:
1、strtok是不可重入的(strtok_r是strtok的可重入版本),strseq是可重入的。
2.strsep和strtok都对修改了src字符串。所以不能使用字符串常量作为分割字符串。
3.strsep和strtok对字符串分割结果不一致。若被分割的字符串有连续的多个分割符出现,strtok会返回NULL,而strsep会返回空串;因此,我们若想用strsep分割字符串,必须进行返回值是否为空的检验。
4、最好使用strsep;尽量避免使用strtok。