用C中的多字符分隔符拆分字符字符串

Sad*_*hir 4 c string parsing tokenize delimiter

我想char *string根据多字符分隔符拆分 a 。我知道它strtok()用于拆分字符串,但它适用于单字符分隔符。

我想根据子字符串(例如"abc"或任何其他子字符串)拆分 char * string 。如何实现?

Jer*_*fin 6

找到所需序列发生的点非常容易:strstr支持:

char str[] = "this is abc a big abc input string abc to split up";
char *pos = strstr(str, "abc");
Run Code Online (Sandbox Code Playgroud)

因此,此时,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;
}
Run Code Online (Sandbox Code Playgroud)

这确实有效。例如:

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

产生大致预期的输出:

this is
 a big
 input string
 to split up
Run Code Online (Sandbox Code Playgroud)

尽管如此,它很笨拙,难以使线程安全(您必须使其内部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");
    }
}
Run Code Online (Sandbox Code Playgroud)

不过,我想我现在暂时搁置它——为了获得一个真正干净的界面,我们真的想重新发明一些像协程这样的东西,在这里发布可能有点多。