概述
在c语言中,字符串分割函数主要有两种:一是strtok函数,另一个就是strsep函数。
下面我们对这两个函数作一个详细解释说明。
对比项 | strtok | strsep |
功能 | 根据一组分隔符对字符串进行分割 | 根据一组分隔符对字符串进行分割 |
是否修改原始字符串 | 是 | 是 |
线程安全性 | 不是线程安全的 | 是线程安全的 |
处理相邻分隔符的方式 | 如果两个分隔符相邻,它会将它们视为一个 | 如果两个分隔符相邻,它会将它们视为两个,并在它们之间返回一个空字符串 |
返回值 | 返回指向分隔符之前的第一个字符的指针,同时将分隔符替换为 ‘\0’ | 返回指向分隔符之前的第一个字符的指针,同时将分隔符替换为 ‘\0’ |
用途 | 用于解析简单的、格式固定的字符串,如 CSV 文件 | 用于解析复杂的、格式可变的字符串,如 HTTP 请求头 |
strsep - extract token from string(linux 下)
#include <string.h> char *strsep(char **s, const char *delim); //会修改数据源。可重入的,注意这里虽然改动stringp的内容,主要是不在使用static静态变量了。
作用:
stringp为指向欲分割的字符串,delim为分隔符,函数将返回分隔符前面的字符串,stringp将指向分隔符之后的字符串。
Be cautious when using this function. If you do use it, note that:
This function modifies its first argument.
This function cannot be used on constant strings.
The identity of the delimiting character is lost.
strtok, strtok_r - extract tokens from strings
#include <string.h> char *strtok(char *str, const char *delim); //会修改数据源。外部加锁才线程安全(strtok执行结束再解锁执行另一个strtok循环知道工作完成) char *strtok_r(char *str, const char *delim, char **saveptr);
代码示例:*
#include <string.h> #include <stdio.h> int main(int arg, const char *argv[]) { /*字符串不能为常量*/ char* string = strdup("/home/yinlijun/project:/home/yinlijun:/home/someone"); char* p; while((p = strsep(&string, ":")) != NULL) /*第一个参数设为二级指针,字符串中所有的第二个参数(子串)最后会被替代成‘/0’*/ { printf("%s/n", p); } free(string); return 0; }
相同点
对该函数的调用序列将str拆分为token,这些token是由作为定界符一部分的任何字符分隔的连续字符的序列。
首次调用时,该函数需要一个C字符串作为str的参数,该字符串的第一个字符用作扫描令牌的起始位置。
在随后的调用中,该函数需要一个空指针,并使用最后一个标记结束后的位置作为扫描的新起始位置。
为了确定token的开头和结尾,该函数首先从起始位置扫描未包含在定界符中的第一个字符(该字符成为token的开头)。
然后从token的开头开始扫描定界符中包含的第一个字符,该字符成为token的末尾。如果找到终止的空字符,扫描也会停止。
token的此结尾将自动替换为空字符(NULL),并且token的开头由函数返回。
一旦在对strtok的调用中找到了str的终止null字符,此函数的所有后续调用(将null指针作为第一个参数)都将返回null指针。
找到下一个标记的点由在下一次调用时使用的函数在内部保留(不需要特殊的库实现来避免数据争用)。
两者都会对原字符串进行修改。
不同点
- strtok内部记录上次调用字符串的位置,所以是不可重入的,不支持多线的,其可重入版本为strtok_r。
- strsep使用传入的参数来确定字符串的起始位置,是可重入的,也是Linux kernel推荐的函数,strtok的替代品。
- strtok()是被标准化(C标准,并因此也通过POSIX),
但strsep()不规范(由C或POSIX;它是GNU C库中可用的,和起源于BSD).因此,可移植的代码strtok()比strsep().更容易使用- strtok()允许在单个标记之间使用多个分隔符,而strsep()期望标记之间使用单个分隔符,并将相邻分隔符解释为空标记.
什么时候使用它们?
- 使用strsep函数,当您需要处理空字段,或者在不同字段之间使用单个分隔符,并且在不介意可移植性的情况下。
- 使用strtok_r函数,当您希望在字段之间允许多个分隔符,不需要处理空字段,并且要求代码具有良好的POSIX兼容性。
- 尽量避免使用strtok函数,因为它是不可重入的,容易导致问题。尤其在多线程环境中,strtok的使用可能导致程序出现不稳定的行为。
您可以strsep()在需要空字段时使用,而不是在字段之间允许多个分隔符,并且在您不介意可移植性时使用.
你会使用strtok_r(),当你想允许标记之间的多个分隔符,你不想空字符(和POSIX足够的便携式你).
strtok()如果你不这样做,你只会在有人威胁你的生命时使用.而你只能用它足够长的时间让你摆脱危及生命的境地; 然后你会再次放弃使用它.它有毒; 不要使用它.编写自己的strtok_r()或者strsep()使用它会更好strtok().为什么strtok()有毒?
strtok()如果在库函数中使用,该函数是有毒的.如果您的库函数使用strtok(),则必须清楚地记录.
那是因为:
- 如果任何调用函数正在使用strtok()并调用也使用的函数strtok(),则会中断调用函数.
- 如果你的函数调用任何调用的函数strtok(),那将破坏你的函数的使用strtok().
- 如果您的程序是多线程的,那么strtok()在任何给定时间最多只能有一个线程使用- 跨越一系列strtok()调用.
此问题的根源是调用之间保存的状态,允许strtok()在停止的位置继续.除了"不要使用strtok()" 之外,没有合理的方法来解决问题.
- strsep()如果可用,您可以使用.
- 您可以使用POSIX(strtok_r()如果可用).
- strtok_s()如果可用,您可以使用Microsoft .
- 名义上,您可以使用ISO/IEC 9899:2011附件K.3.7.3.1功能strtok_s(),但其界面strtok_r()与微软的界面不同strtok_s()