C strtok,如果我想保留分隔符怎么办?

标签 c string strtok

我正在尝试分割以下类型的行:

GM 1 2 3 ! this is a comment

分离出评论部分。有几种可能的注释分隔符:!、' 和 #。 strtok 是明显的解决方案:

card->card_str = strtok(line_buf, "!'#");

生成GM 1 2 3这是一条评论。但是,对于这个角色,我需要将分隔符保留在第二个字符串中,因此在本例中 !这是一条评论。有没有简单的方法可以做到这一点?

最佳答案

strtok 很少是解析作业的正确工具,因为它有很多怪癖和副作用。

为了实现您的目标,您可以使用strcspn():

void parse_input_line(const char *line) {
    size_t len = strcspn(line, "!'#");
    char *p = malloc(len + 1);
    if (p != NULL) {
        memcpy(p, line, len);
        p[len] = '\0';
        card->card_str = p;
        card->card_comment = p[len] ? strdup(p + len) : NULL;
    }
}

或者,您可以使用strpbrk:

void parse_input_line(const char *line) {
    const char *sep = strpbrk(line, "!'#");
    if (sep == NULL) {
        // no comment
        card->card_str = strdup(line);
        card->card_comment = NULL;
    } else {
        size_t len = sep - line;
        char *p = malloc(len + 1);
        if (p != NULL) {
            memcpy(p, line, len);
            p[len] = '\0';
            card->card_str = p;
            card->card_comment = strdup(sep);
        }
    }   
}

您可以使用strndup使代码更具可读性:

void parse_input_line(const char *line) {
    size_t len = strcspn(line, "!'#");
    if (p[len] == '\0') {
        /* no comment */
        card->card_str = strdup(line);
        card->card_comment = NULL;
    } else {
        card->card_str = strndup(line, len);
        card->card_comment = strdup(p + len);
    }
}

strndup 可能并非在所有系统上都可用,这里是一个简单的实现:

size_t strnlen(const char *s, size_t n) {
    size_t len;
    for (len = 0; len < n; len++) {
        if (s[len] == '\0')
            break;
    }
    return len;
}

char *strndup(const char *s, size_t n) {
    size_t len = strnlen(s, n);
    char *p = malloc(len + 1);
    if (p != NULL) {
        memcpy(p, s, len);
        p[len] = '\0';
    }
    return p;
}

关于C strtok,如果我想保留分隔符怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49101200/

相关文章:

c - 从文件中扫描字符串,忽略最后一个字符

regex - Golang 替换所有换行符

c - 每次运行程序时 strtok() 的输出都会给出不同的行为

c - 使用strtok分隔单词并删除, and ()

c++ - 如何使用 strtok 对使用 C++ 的表达式进行标记化

C 编译器访问全局 T const * const obj 的未定义行为,其底层对象可能会更改?

c - 将可变长度二维数组传递给函数

c - 使用 SSE/AVX 并行化 C 代码

C++ 使用 boost 对字符串进行标记并将标记保存为字符串

java - StringBuffer 的 insert() 和 deleteCharAt() 方法是如何工作的