1. 問題:Linux C如何切分字符串?
java的String類有split方法,可以將字符串對象按指定字符串進行切分,返回一個數組String[],包含切分后的所有字符串。 Linux C如何對字符串進行切分呢?有沒有類似函數/系統調用?
答:Linux C沒有字符串類,也沒有split函數,不過有切分字符串的方法:strtok函數。
2.strtok函數
提取分隔符間字串。
strok 有2個版本:strok, strok_r。前者適用於單線程,后者是可重入版本,適用於多線程。
strok 在一次切分后,能得到分隔符左邊的字符串。
注意:
1)調用strok會改變傳入的str指向的內容,不能是字符串常量,str指向字符串內容為分隔符delim的部分,會被替換為'\0'。
2)strok是C99, POSIX.1內容,strok_r僅僅是POSIX.1內容。
strok_r 除了具有strok功能,還能在一次切分后,通過saveptr保存分隔符右邊的字符串。
#include <string.h>
char *strtok(char *str, const char *delim);
char *strtok_r(char *str, const char *delim, char **saveptr);
功能
形如"aaa:bbb"的字符串,strok按分隔符":"對其切分后,得到"aaa"(返回值), 剩余"bbb". strtok_r能同時得到"aaa"(返回值),"bbb"(saveptr)。
參數
- str 待切分字符串,必須是可以修改的字符串,不能是字符串常量。
- delim 分隔符
- saveptr 用於保存strtok_r切分后剩余那部分字符串首地址
返回值
成功找到分隔符,返回被切分的第一個子字符串;如果沒有可檢索的字符串,則返回一個空指針。
用法:
除第一次調用strtok, 要指明待切分字符串, 后續無需指定, 要用NULL
形如
strtok(buf, " "); /* 第一次, 空格切分字符串buf */
strtok(NULL, " "); /* 第二次, 空格切分字符串buf */
strtok(NULL, " "); /* 第三次, 空格切分字符串buf */
...
或者
strtok(buf, " "); /* 第一次, 空格切分字符串buf */
while (( p = strtok(NULL, " ") != NULL) { /* 第二次到第n次切分buf */
printf("%s\n", p);
}
3. strtok切分字符串示例
char buf[] = "USER 123456 abc @88890\n";
printf("primary buf = %s\n", buf);
char *s1 = strtok(buf, " "); /* <SP>切分buf */
char *s2;
printf("%s\n", s1);
while ((s2 = strtok(NULL, " ")) != NULL) {
printf("%s\n", s2);
}
printf("splited buf = %s\n", buf);
運行結果:
primary buf = USER 123456 abc @88890
USER
123456
abc
@88890
splited buf = USER
可以看到,原始字符串buf被修改了。實際上,是buf中分隔符所在位置,都被替換成了'\0'。
4. strtok_r使用示例
利用strtok_r,將字符串buf按分隔符" "(空格)分隔為2部分,分別保存到s1, s2 (2個char *)
char buf[] = "USER 123456 abc @88890\n";
char *s1;
char *s2;
printf("primary buf = %s\n", buf);
s1 = strtok_r(buf, " ", &s2);
printf("s1 = %s\n", s1);
printf("s2 = %s\n", s2);
printf("strtok_r buf = %s\n", buf);
運行結果:
primary buf = USER 123456 abc @88890
s1 = USER
s2 = 123456 abc @88890
strtok_r buf = USER
5. 自定義字符串函數split實現
受4的啟發,strtok_r將字符串buf分隔為2部分,分別用2個char *指針標記。
4的問題是,2個char *指針,並未保存切分后字符串,指示用2個指針保存了原來緩存中的切分位置。能否實現一個函數,將字符串切分后,保存到2個字符串緩存?
答:是可以的,自定義切分函數strex_split
實現見下
void strex_split(char *s, char *left, char *right, const char* delim)
{
char *s1, *s2;
s1 = strtok_r(s, delim, &s2);
strcpy(left, s1);
strcpy(right, s2);
}
其中,left, right是需要調用者提供的緩存。