对于一些高级语言而言,使用某个字符分割字符串是很基础的功能。而对于编程语言中的瑞士军刀C,该功能自然也是有的,我们使用标准C提供的strtok函数即可实现这个功能。这个函数在使用上面看上去有些怪,我们从一个例子开始吧。
一,strtok基本使用
#include <stdio.h>
#include <string.h>
int main()
{
char *token;
char line[] = "ab,c:d e fngh";
char *delims = ",: tn";
/* 第一次调用strtok时第一个参数为要处理的字符串 */
token = strtok(line, delims);
while (token != NULL)
{
printf ( "%sn", token );
/* 后续调用传NULL */
token = strtok(NULL, delims);
}
return 0;
}
程序执行结果如下:
ab
c
d
e
f
gh
然后再看下strtok的函数原型:
char *strtok(char *str, const char *delim);
strtok的第一个参数毫无疑问就是我们想要处理的字符串,第二个参数是分割符。这里注意第二个参数是字符串,而不是字符。因为strtok支持使用多个分割字符分割字符串,甚至在每次调用strtok的时候可以重新指定分割符。
strtok的使用方法:strtok第一次调用的时候str参数传我们要处理的字符串,后续再调用的时候第一个参数传NULL。然后我们多次调用strtok,直到返回NULL则解析结束。每一次调用,返回分割得到的字符串,该字符串包含字符串结束符。
二,strtok实现细节及使用时的注意事项
我们看一下glic中strtok的实现:
#include <string.h>
static char *olds;
#undef strtok
#ifndef STRTOK
# define STRTOK strtok
#endif
/* Parse S into tokens separated by characters in DELIM.
If S is NULL, the last string strtok() was called with is
used. For example:
char s[] = "-abc-=-def";
x = strtok(s, "-"); // x = "abc"
x = strtok(NULL, "-="); // x = "def"
x = strtok(NULL, "="); // x = NULL
// s = "abc=-def"
*/
char *
STRTOK (char *s, const char *delim)
{
char *token;
if (s == NULL)
s = olds;
/* Scan leading delimiters. */
s += strspn (s, delim);
if (*s == '')
{
olds = s;
return NULL;
}
/* Find the end of the token. */
token = s;
s = strpbrk (token, delim);
if (s == NULL)
/* This token finishes the string. */
olds = __rawmemchr (token, '');
else
{
/* Terminate the token and make OLDS point past it. */
*s = '';
olds = s + 1;
}
return token;
}
可以看到,其实strtok就是一个循环字符串解析的过程,解析过程这里就不详细分析了,有兴趣的可以自己研究一下这段代码。但从这个实现中我们可以得出一些使用strtok的注意点:
1, strtok会改变传给它的字符串(代码里面的s = ''),细心的人可能已经发现它的第一个参数不是const的。所以我们一定得保证传的字符串是可以更改的。最常见的错误是给strtok传一个char的字符串字面常量(这样可能会导致段错误):
char *str1 = "hello world";
char str2[] = "hello world";
注意,上面的str1就是字符串字面常量,这种定义方法定义的字符串是常量字符串,是const的,是不可以改变的。诸如str1[1] = 'c';的赋值操作都是不允许的。而str2的定义方法则只是一个普通的数组,是可以更改的。
2, 连续的分割符都会被跳过。这个是什么意思呢?举个例子:比如对于字符串"ab::cd:",我们使用分割符":"分割的时候,返回值是"ab"、"cd"、NULL,而不是"ab"、""(空字符串)、"cd"、NULL。
3, 如果目标字符串是空或者只包含分割符,那么我们第一次调用strtok的时候,就会返回NULL。
最后简单介绍以下上面glic实现strtok时使用的几个库函数:
#include <string.h>
size_t strspn(const char *s, const char *accept);
size_t strcspn(const char *s, const char *reject);
char *strpbrk(const char *s, const char *accept);
strspn()从参数s 字符串的开头计算连续的字符,而这些字符都完全是accept 所指字符串中的字符。简单的说,若strspn()返回的数值为n,则代表字符串s 开头连续有n 个字符都是属于字符串accept内的字符。
strcspn()从参数s 字符串的开头计算连续的字符, 而这些字符都完全不在参数reject 所指的字符串中. 简单地说, 若strcspn()返回的数值为n, 则代表字符串s 开头连续有n 个字符都不含字符串reject 内的字符.
strpbrk是在源字符串(s1)中找出最先含有搜索字符串(s2)中任一字符的位置并返回,若找不到则返回空指针。
评论已关闭