我想根据多字符分隔符拆分char *string
。我知道strtok()
用于分割字符串,但它适用于单字符分隔符。
我想基于诸如"abc"
之类的子字符串或任何其他子字符串来拆分char * string。如何实现?
答案 0 :(得分:3)
找到所需序列发生的位置非常简单:strstr
支持:
char str[] = "this is abc a big abc input string abc to split up";
char *pos = strstr(str, "abc");
因此,在此时,pos
指向较大字符串中abc
的第一个位置。事情变得有点难看。 strtok
有一个令人讨厌的设计,它1)修改原始字符串,2)在内部存储指向字符串中“当前”位置的指针。
如果我们不介意大致相同,我们可以这样做:
char *multi_tok(char *input, char *delimiter) {
static char *string;
if (input != NULL)
string = input;
if (string == NULL)
return string;
char *end = strstr(string, delimiter);
if (end == NULL) {
char *temp = string;
string = NULL;
return temp;
}
char *temp = string;
*end = '\0';
string = end + strlen(delimiter);
return temp;
}
这确实有效。例如:
int main() {
char input [] = "this is abc a big abc input string abc to split up";
char *token = multi_tok(input, "abc");
while (token != NULL) {
printf("%s\n", token);
token = multi_tok(NULL, "abc");
}
}
产生大致预期的产出:
this is
a big
input string
to split up
尽管如此,它是笨拙的,难以使线程安全(你必须使其内部string
变量线程本地)并且通常只是一个糟糕的设计。使用(例如)类似strtok_r
的接口,我们至少可以解决线程安全问题:
typedef char *multi_tok_t;
char *multi_tok(char *input, multi_tok_t *string, char *delimiter) {
if (input != NULL)
*string = input;
if (*string == NULL)
return *string;
char *end = strstr(*string, delimiter);
if (end == NULL) {
char *temp = *string;
*string = NULL;
return temp;
}
char *temp = *string;
*end = '\0';
*string = end + strlen(delimiter);
return temp;
}
multi_tok_t init() { return NULL; }
int main() {
multi_tok_t s=init();
char input [] = "this is abc a big abc input string abc to split up";
char *token = multi_tok(input, &s, "abc");
while (token != NULL) {
printf("%s\n", token);
token = multi_tok(NULL, &s, "abc");
}
}
我想我现在就把它留在那里 - 为了得到一个非常干净的界面,我们真的想重新发明类似协程的东西,这可能有点多发布在这里。
答案 1 :(得分:1)
您可以使用strstr()
轻松编写自己的解析器来实现相同的目标。基本算法可能如下所示
strstr()
查找整个分隔符字符串的第一个匹配项答案 2 :(得分:1)
编辑:考虑了Alan和Sourav的建议,并为此编写了基本代码。
#include <stdio.h>
#include <string.h>
int main (void)
{
char str[] = "This is abc test abc string";
char* in = str;
char *delim = "abc";
char *token;
do {
token = strstr(in,delim);
if (token)
*token = '\0';
printf("%s\n",in);
in = token+strlen(delim);
}while(token!=NULL);
return 0;
}
答案 3 :(得分:0)
我写了一个线程安全的简单实现:
struct split_string {
int len;
char** str;
};
typedef struct split_string splitstr;
splitstr* split(char* string, char* delimiter) {
int targetsize = 0;
splitstr* ret = malloc(sizeof(splitstr));
if (ret == NULL)
return NULL;
ret->str = NULL;
ret->len = 0;
char* pos;
char* oldpos = string;
int newsize;
int dlen = strlen(delimiter);
do {
pos = strstr(oldpos, delimiter);
if (pos) {
newsize = pos - oldpos;
} else {
newsize = strlen(oldpos);
}
char* newstr = malloc(sizeof(char) * (newsize + 1));
strncpy(newstr, oldpos, newsize);
newstr[newsize] = '\0';
oldpos = pos + dlen;
ret->str = realloc(ret->str, (targetsize+1) * sizeof(char*));
ret->str[targetsize++] = newstr;
ret->len++;
} while (pos != NULL);
return ret;
}
使用:
splitstr* ret = split(contents, "\n");
for (int i = 0; i < ret->len; i++) {
printf("Element %d: %s\n", i, ret->str[i]);
}