字符串分割
strtok()函数
char* strtok(char* str, const char* delimiters)
str
是要被分割的字符串,str
将被修改,所以str
不能为字符串常量。
delimiters
是分割符的集合
#include<stdio.h>
#include<string.h>
int main()
{
char str[20] = "abc def";
const char* delimiters = " ";
char s1[10] = {0};
char s2[10] = {0};
char* p = strtok(str, delimiters);
strcpy(s1, p);
if(p != NULL)
{
p = strtok(NULL, delimiters);
}
printf("s1 = %s s2 = %s\n", s1, s2);
system("pause");
return 0;
}
分析一波:
第一次调用strtok()函数时,strtok()将会找到第一个分割符的位置,让后将这个分割符替换成NULL
,然后返回一个指向a
的指针。也就是相当于返回了字符串abc
。
第二次调用strtok()函数时,传的参数是(NULL, delimiters),因为第一个参数为NULL
,strtok()函数会使用之前存储的字符串,因为strtok()函数内部有个static变量保存了之前使用过的字符串信息。所以strtok()函数是不可重入函数,也既是线程不安全函数。这时候strtok()函数会继续找下一个delimiters,在字符串 abc def
中当然是找不到的,而且遍历到了字符串末尾,所以返回指向 d
的指针。
如果此时再调用strtok(NULL, delimiters)函数,将会返回NULL,因为此时static变量指向了字符串 abc def
的末尾。
如果 delimiters
中的分割符不只一个,那么遇到每个分割符都会进行分割。
strtok_r()函数
char* strtok_r(char* str, const char* delim, char** saveptr)
str
是要被分割的字符串,str
将被修改,所以str
不能为字符串常量。
delimiters
是分割符的集合
saveptr
是指向分割符后的第一个字符,第一次传入时为NULL
strtok_r()函数实现
char *strtok_r(char *s, const char *delim, char **save_ptr)
{
char *token;
if (s == NULL) s = *save_ptr;
/* Scan leading delimiters. */
s += strspn(s, delim);
if (*s == '\0') return NULL;
/* Find the end of the token. */
token = s;
s = strpbrk(token, delim);
if (s == NULL)
/* This token finishes the string. */
*save_ptr = strchr(token, '\0');
else
{
/* Terminate the token and make *SAVE_PTR point past it. */
*s = '\0';
*save_ptr = s + 1;
}
return token;
}
代码整体的流程如下:
- 判断参数s是否为NULL,如果是NULL就以传递进来的save_ptr作为起始分解位置;若不是NULL,则以s开始切分。
- 跳过待分解字符串开始的所有分界符。
- 判断当前待分解的位置是否为’\0’,若是则返回NULL;不是则继续。
- 保存当前的待分解串的指针token,调用strpbrk在token中找分界符:如果找不到,则将save_ptr赋值为待分解串尾部’\0’所在的位置,token没有发生变化;若找的到则将分界符所在位置赋值为’\0’,token相当于被截断了(提取出来),save_ptr指向分界符的下一位。
- 函数的最后(无论找到还是没找到)都将返回。
strtok()函数实现
char* strtok(char* s, const char* delim)
{
static char* p = NULL;
return strtok_r(s, delim, &p);
}
来看个例子
将 char buffer[] = "Fred male 25,John male 62,Anna female 16";
以空格和逗号为分割符进行分割。
#include<stdio.h>
#include<string.h>
char* strtok_r(char* s, const char* delim, char** save_ptr);
int main()
{
int in = 0;
char buffer[100] = "Fred male 25,John male 62,Anna female 16";
char *p[20];
char *buf = buffer;
char *outer_ptr = NULL;
char *inner_ptr = NULL;
while ((p[in] = strtok_r(buf, ",", &outer_ptr)) != NULL)
{
buf = p[in];
while ((p[in] = strtok_r(buf, " ", &inner_ptr)) != NULL)
{
in++;
buf = NULL;
}
buf = NULL;
}
printf("Here we have %d strings\n", in);
for (int j = 0; j<in; j++)
{
printf(">%s<\n", p[j]);
}
system("pause");
return 0;
}
这个例子中用了两层循环,先将 buffer
在外循环中按照逗号分割,然后在内循环中按照空格分割,将分割好的字符串保存在指针数组 p
中便于打印。
c++中实现分割字符串
vector<string> splitstr(string& str, const string& delim)
{
vector<string> result;
size_t pos1 = str.find_first_not_of(delim, 0);
size_t pos2 = str.find_first_of(delim, pos1);
if (pos1 == string::npos || pos2 == string::npos)
{
result.push_back(str);
}
while (pos1 != string::npos || pos2 != string::npos)
{
result.push_back(str.substr(pos1, pos2-pos1));
pos1 = str.find_first_not_of(delim, pos2);
pos2 = str.find_first_of(delim, pos1);
}
return result;
}
str.find_first_not_of(delime, 0)
从 0
位置开始找到 str
中第一个不属于 delim
中的字符,返回这个字符的位置。
str.find_first_of(delim, pos1)
从 pos1
位置开始找到 str
中第一个属于 delim
中的字符,返回这个字符的位置。
str.substr(pos1, n)
从 pos1
开始,提取 str
中 n
个字符,将这些字符以一个新的 string
返回。
参考:https://www.cnblogs.com/zhouhbing/p/4103916.html
参考:https://www.cnblogs.com/happykoukou/p/5427268.html