从strtok()获取零长度字符串

我有一个包含数据的CSV文件

value;name;test;etc 

我试图通过使用strtok(string, ";")进行拆分。 但是,此文件可以包含零长度数据,如下所示:

 value;;test;etc 

哪个strtok()跳过。 有没有办法可以避免strtok像这样跳过零长度数据?

可能的替代方法是使用BSD函数strsep()而不是strtok() (如果可用)。 从手册页 :

strsep()函数旨在替代strtok()函数。 虽然strtok()函数应该是出于可移植性的首选(它符合ISO / IEC 9899:1990(“ISO C90”)),但它无法处理空字段,即检测由两个相邻分隔符字符分隔的字段,或者一次用于多个字符串。 strsep()函数首先出现在4.4BSD中。

一个简单的例子(也从该手册页复制):

 char *token, *string, *tofree; tofree = string = strdup("value;;test;etc"); while ((token = strsep(&string, ";")) != NULL) printf("token=%s\n", token); free(tofree); 

输出:

标记=值
令牌=
标记=测试
标记=等

所以空字段处理正确。

当然,正如其他人已经说过的,这些简单的tokenizer函数都没有正确处理引号内的分隔符,所以如果这是一个问题,你应该使用一个合适的 CSV解析库。

没有办法让strtok()不这样做。 从手册页 :

解析后的字符串中的两个或多个连续分隔符字节的序列被视为单个分隔符。 字符串开头或结尾的分隔符字节将被忽略。 换句话说:strtok()返回的标记总是非空的字符串。

但你可以做的是检查令牌之前'\0'字符的数量,因为strtok()'\0'替换所有遇到的令牌。 这样你就会知道有多少令牌被跳过了。 来源信息 :

令牌的这一端自动替换为空字符,并且该函数返回令牌的开头。

并提供代码示例以显示我的意思。

 char* aStr = ...; char* ptr = NULL; ptr = strtok (...); char* back = ptr; int count = -1; do { back--; if (back <= aStr) break; // to protect against reads before aStr count++; } while (*back = '\0'); 

(没有ide或测试的书面,可能是一个无效的实现,但这个想法是站立的)。

不,你不能。 来自“man strtok”:

解析后的字符串中的两个或多个连续分隔符字符的序列被视为单个分隔符。 字符串开头或结尾的分隔符字符将被忽略。 换句话说:strtok()返回的标记总是非空的字符串。

如果您的数据包含引号内的分隔符或任何其他“转义”,您也可能遇到问题。

我认为最好的解决方案是获取CSV解析库或编写自己的解析函数。