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

时间:2013-09-16 12:02:54

标签: c csv strtok

我有一个包含

等数据的CSV文件
value;name;test;etc

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

value;;test;etc

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

3 个答案:

答案 0 :(得分:5)

可能的替代方法是使用BSD函数strsep()而不是strtok()(如果可用)。 来自man page

  

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

输出:

token=value
token=
token=test
token=etc

所以空字段处理正确。

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

答案 1 :(得分:4)

没有办法让strtok()不这样做。来自man page

  

解析后的两个或多个连续分隔符字节的序列   string被认为是一个单独的分隔符。分隔符字节在   字符串的开头或结尾被忽略。换句话说:代币   由strtok()返回的字符串总是非空字符串。

但您可以执行的操作是检查令牌之前'\0'个字符的数量,因为strtok()会将所有遇到的令牌替换为'\0'。这样你就会知道有多少令牌被跳过了。 Source info

  

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

代码示例以显示我的意思。

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或测试的书面,可能是一个无效的实现,但这个想法代表)。

答案 2 :(得分:2)

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

  

一个包含两个或多个连续分隔符的序列   解析的字符串被认为是单个分隔符。分隔符   字符串开头或结尾的字符将被忽略。放   另一种方式:strtok()返回的标记总是非空的   字符串。

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

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