1. 程式人生 > 其它 >Linux C strtok實現自定義字串切分函式split

Linux C strtok實現自定義字串切分函式split


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是需要呼叫者提供的快取。