strtok 快速上手char *strtok(char *str, const char *delim);
str,函數內部靜態記錄位置。str 傳 NULL,繼續從上次位置分割。delim 中任意字符均視為分隔符,連續分隔符被視為一個,不產生空串。NULL。char s[] = "abc,def;ghi"; // 必須可修改數組,不可用字面量
char *d = ",;";
char *t = strtok(s, d);
while (t) {
puts(t);
t = strtok(NULL, d); // 關鍵:傳 NULL 繼續分割
}
// 輸出:abc / def / ghi
strtok 會在分隔符處寫入 \0,原字符串被切碎。需分割副本:char *copy = strdup(s);。strtok_s,POSIX 有 strtok_r(需 _GNU_SOURCE)。delim="##" 視為 '#' 和 '#' 兩個單字符分隔符,而非子串 "##"。若需按子串分割,strtok 無能為力。作者原版實現(按完整匹配分隔符串分割):
void strsplit(const char *str, const char *delim,
void (*visitor)(const char *, int start, int end)) {
int s_len = strlen(str), d_len = strlen(delim);
int k_s = 0, k_e = 0;
while (k_e < s_len) {
if (k_e + d_len <= s_len && strncmp(str + k_e, delim, d_len) == 0) {
if (k_e > k_s) visitor(str, k_s, k_e); // 回調處理 token
k_s = k_e = k_e + d_len; // 跳過整個分隔符串
} else {
k_e++;
}
}
if (k_e > k_s) visitor(str, k_s, k_e); // 尾部 token
}
關鍵差異:strtok("a##b", "#") → "a", "b";自定義 strsplit("a##b", "##") → "a", "b";但 strsplit("a#b", "##") → "a#b" (無分割),而 strtok 會分割。
strtok 行為(單字符分隔符集合)只需將跳過邏輯改為 k_e++; k_s = k_e; 即可實現「任意分隔符字符單獨切分」語義。
| 場景 | 推薦方案 |
|---|---|
| 單線程、簡單分隔符、可修改原串 | strtok 最簡潔 |
| 多線程 / 需保留原串 | strtok_r / strtok_s 或手寫 |
| 多字符分隔符串(如 "::" "--") | 手寫 strsplit 或 strstr 循環 |
| 高性能解析(如 CSV、日志) | 手寫狀態機,避免函數調用開銷 |