strtok / strtok_r退出中间解析

时间:2015-09-04 09:27:16

标签: c performance tokenize strtok

unbuffer在解析时将空字符放入输入字符串的不同位置。仅在strtok_r返回strtok_r后才会恢复原始字符串。

如果我需要在长字符串的开头附近提取令牌怎么办?如果我离开循环,输入字符串将保持断开状态。我可以尝试手动恢复分隔符,但我不知道它是否是最后一个令牌。 问题是没有记录NULL值。

saveptr

1 个答案:

答案 0 :(得分:2)

strtok()和strtok_r()是可怕的功能:

  • 他们修改输入字符串
  • 它们将连续分隔符视为一个分隔符,这可能在跳过空格时有意,但在解析.CSV(或制表符分隔)输入时不是这样。

最好是完全避免使用strtok()和strtok_r(),并使用strspn()和strcspn()。以下功能就是这样。返回值类似于snprintf()的值:找到的令牌中的字符数(不计算终止的NUL字节)

  • 如果没有令牌#n:' \ 0'被写入缓冲区并返回0
  • 如果缓冲区对于找到的令牌而言太小而加上终止的NUL字节,' \ 0'写入缓冲区并返回令牌长度
  • 是缓冲区足够大,令牌+' \ 0'写入,并返回strlen(令牌)。
#include <stdio.h>
#include <string.h>

size_t extract_nth_token_ohne_strtok_r(char *res, size_t maxlen, const char *str, const char *delim, int n)
{
size_t pos, len;
int itok;

for (itok=0,pos=0; str[pos]; ) {
        len = strcspn(str+pos, delim);
        if (itok++ == n) {
                if (len < maxlen) memcpy(res, str+pos, len), res[len] = 0;
                else res[0] = 0;
                return len;
                }
        pos += len;
        if (str[pos]) pos++;
        }
res[0] = 0;
return 0;
}

int main(void)
{
char * omg = "zero one\ttwo \tfour\nfive" ;
char token[80];
size_t toklen;
int ii;

printf("\n## With a large enough buffer:\n" );
for (ii=0; ii < 7; ii++) {
        toklen = extract_nth_token_ohne_strtok_r(token, sizeof token
                , omg, " \t\n", ii);
        printf("%d: res=%zu \"%s\"\n" , ii, toklen, token );
        }

printf("\n## With 4-character buffer:\n" );
for (ii=0; ii < 7; ii++) {
        toklen = extract_nth_token_ohne_strtok_r(token, 4
                , omg, " \t\n", ii);
        printf("%d: res=%zu \"%s\"\n" , ii, toklen, token );
        }

return 0;
}

注意:如果你想要将连续的whitspace视为一个,你可以将if (str[pos]) pos++;替换为:

pos += strspn(str+pos, delim);