C/C++ 字符串分割: strtok 与 strsep 函数说明
函数原型:
char *strtok(char *s, const char *delim);
char *strsep(char **s, const char *delim);
功能:strtok和strsep两个函数的功能都是用来分解字符串为一组字符串。s为要分解的字符串,delim为分隔符字符串。
返回值:从s开头开始的一个个子串,当没有分割的子串时返回NULL。
相同点:两者都会改变源字符串,想要避免,可以使用strdupa(由allocate函数实现)或strdup(由malloc函数实现)。
strtok函数第一次调用时会把s字符串中所有在delim中出现的字符替换为NULL。然后通过依次调用strtok(NULL, delim)得到各部分子串。
作用:
分解字符串为一组字符串。s为要分解的字符串,delim为分隔符字符串。
说明:
strtok()用来将字符串分割成一个个片段。参数s指向欲分割的字符串,参数delim则为分割字符串,当strtok()在参数s的字符串中发现到参数delim的分割字符时则会将该字符改为\0 字符。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回下一个分割后的字符串指针。
返回值:
从s开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。
所有delim中包含的字符都会被滤掉,并将被滤掉的地方设为一处分割的节点。(如下面的例子,可修改 seps里面的数据,然后看输出结果)
#include <string.h> #include <stdio.h> char string[] ="A string\tof ,,tokens\nand some more tokens"; char seps[] =" ,\t\n"; char *token; int main( void ) { printf( "%s\n\nTokens:\n", string ); /* Establish string and get the first token: */ token = strtok( string, seps ); while( token != NULL ) { /* While there are tokens in "string" */ printf( " %s\n", token ); /* Get next token: */ token = strtok( NULL, seps ); } return 0; }
总结:
strtok内部记录上次调用字符串的位置,所以不支持多线程,可重入版本为strtok_r,有兴趣的可以研究一下。它适用于分割关键字在字符串之间是“单独”或是 “连续“在一起的情况。
strsep:
#include <string.h> #include <stdio.h> char string[] ="A string\tof ,,tokens\nand some more tokens"; char seps[] =" ,\t\n"; char *token, *s; int main( void ) { printf( "%s\n\nTokens:\n", string ); /* Establish string and get the first token: */ s=string; token = strsep( &s, seps ); while( token != NULL ) { /* While there are tokens in "string" */ printf( " %s\n", token ); /* Get next token: */ token = strsep( &s, seps ); } return 0; }
为什么用strtok时子串中间没有出现换行,而strsep却有多个换行呢?文档中有如下的解释:
One difference between strsep and strtok_r is that if the input string contains more
than one character from delimiter in a row strsep returns an empty string for each
pair of characters from delimiter. This means that a program normally should test
for strsep returning an empty string before processing it.
大意是:如果输入的串的有连续的多个字符属于delim,(此例source中的逗号+空格,感叹号+空格等就是这种情况),strtok会返回NULL,而strsep会返回空串 ""。因而我们如果想用strsep函数分割字符串必须进行返回值是否是空串的判断。这也就解释了strsep的例子中有多个换行的原因。
改进后的代码:
效果:
其中, 字符‘\0’ 的 10进制数为0 , 宏定义为 NULL 。
下面的说明摘自于最新的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
*/
总结:
strsep返回值为分割后的开始字符串,并将函数的第一个参数指针指向分割后的剩余字符串。它适用于分割关键字在两个字符串之间只严格出现一次的情况。
PS:
因为函数内部会修改原字符串变量,所以传入的参数不能是不可变字符串(即文字常量区)。
如 char *tokenremain ="abcdefghij"//编译时为文字常量,不可修改。
strtok(tokenremain,"cde");
strsep(&tokenremain,"cde");
编译通过,运行时会报段错误。
相关文章
- C++ string 大小写转换
- C++最好的图形库是什么?
- 托管C++线程锁实现 c++11线程池
- C++ 继承
- 如何编写 C++ 无序容器的哈希函数
- 57 C++ - 函数模板
- C++第7周任务1-求两数正差值
- 【转】 谈谈C++中的swap函数
- 参考开源项目实现一个简易的C++枚举转字符串的函数
- C++中一些方便的算法函数和吃不够的语法糖
- 使用c++filt命令还原C++编译后的函数名
- 《Visual C++ 开发从入门到精通》——第2章 C++的基本语法2.1 面向对象
- 《C++面向对象高效编程(第2版)》——2.16 识别成员函数的目标对象
- 《21天学通C++(第7版)》——12.4 函数运算符operator()
- C++Primer第五版学习(函数部分 三)
- 基于C++数据结构双向循环链表实现的贪吃蛇【100010175】
- 学习opencv: 获取图像最大连通域 c++和python版
- Java vs C++:子类覆盖父类函数时缩小可访问性的不同设计
- C++装饰者模式
- C++编程——函数模板
- C/C++字符串查找函数
- 【华为OD机试真题 java、jsNode、c++】异常的打卡记录【2022 Q4 100分】
- 【C/C++】C语言复制字符串及复制函数汇总(strcpy()/memcpy()/strncpy()/memmove())
- C++ string中的find()函数
- pch”预编译头文件来自编译器的其他版本,或者预编译头为 C++ 而在 C 中使用它(或相反) and vs找不到路径
- C/C++ 指针函数与函数指针