带有无效分隔符的字符串标记化

时间:2015-10-02 00:01:23

标签: c tokenize c-strings

其手册页中strsep()的说明指出,在到达第一个分隔符时,

  

通过使用空字节('\0')覆盖分隔符来终止此标记,并更新*stringp以指向令牌。

其中*stringp是输入字符串。

我想知道是否有任何函数只会更新*stringp以指向令牌而不用'\0'替换分隔符。我有3个可能的分隔符,我可以将其作为strsep()输入到" \t\n",因此像strchr()这样只搜索单个分隔符的内容不会有效(不是有效的,在最小)。由于我需要稍后打印完整的字符串,否则我必须执行memcpy()才能在以后打印字符串。

(另外,任何人都可以解释为什么以这种方式实施......?)

1 个答案:

答案 0 :(得分:2)

这是一个实现:

token = non_nulling_strsep(char** stringp, const char* delims);

strsep非常相似,只是它将*stringp设置为实际终止令牌的分隔符,而不是后续字符。与strsep不同,这意味着您可以将*stringp - token视为令牌的长度,这很有用,因为令牌不是以空值终止的,因为它与strsep一样。如果字符串中没有其他标记,*stringp - token将为0,因此您应该测试结束标记扫描循环的条件。

char* non_nulling_strsep (char** stringp, const char* delims) {
  char* token = *stringp + strspn(*stringp, delims);
  *stringp = token + strcspn(token, delims);
  return token;
}

您可以像这样扫描令牌:

{
  char *end = buffer;
  for (char *token = non_nulling_strsep(&end, " \t\n");
       end - token;
       token = non_nulling_strsep(&end, " \t\n")) {
    printf("Found '%.*s'\n", end - token, token);
  }
}

这是另一个可能的界面,可能会更好。这个返回长度(如果没有更多的标记,则返回0)并将字符串指针设置为下一个标记的开头(如果没有更多标记,则将字符串结束)。

size_t next_token(char** tokenp, const char* delims) {
  *tokenp += strspn(*tokenp, delims);
  return strcspn(*tokenp, delims);
}

有了这个,你就像这样循环:

{
  char *token = buffer;
  for (size_t token_len;
       (token_len = next_token(&token, " \t\n"));
       token += token_len) {
    printf("Found '%.*s'\n", token_len, token);
  }
}