【问题标题】:C strtok, what if I want to keep the delimiter?C strtok,如果我想保留分隔符怎么办?
【发布时间】:2018-08-12 13:28:48
【问题描述】:

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

GM 1 2 3 ! this is a comment

分开评论部分。有几种可能的注释分隔符,!、' 和 #。 strtok 是显而易见的解决方案:

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

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

【问题讨论】:

  • strtok 只是一种快速而肮脏的方式,强调肮脏。如果你想编写自己的分词器,你总是可以通过一个简单的循环来做到这一点。
  • "有没有简单的方法可以做到这一点?"是的,但发布更多代码以显示上下文如何使用 card->card_str
  • 使用strpbrk() 而不是strtok()。就这样。但请注意,this comment 对您来说非常重要。

标签: c string strtok


【解决方案1】:

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;
}

【讨论】:

  • strpbrk(),更像strtok()
  • @IharobAlAsimi:strpbrk也可以用,如图。
  • 这看起来不错,但我在第二种情况下看到两个副本...我不需要 either dup 或 memcpy 吗?
  • @MauryMarkowitz: malloc + memcpy 可以替换为对 strndup 的调用,如果此功能在您的系统上可用。如果没有,它很容易编写并且会使代码更清晰。
猜你喜欢
  • 1970-01-01
  • 2021-11-02
  • 1970-01-01
  • 2016-04-30
  • 2023-02-04
  • 2015-02-26
  • 1970-01-01
  • 2011-06-08
  • 2014-07-17
相关资源
最近更新 更多