【问题标题】:Obtaining zero-length string from strtok()从 strtok() 获取零长度字符串
【发布时间】:2013-09-16 12:02:53
【问题描述】:

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

value;name;test;etc

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

value;;test;etc

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

【问题讨论】:

  • strsep() 在您的平台上可用吗?用法和strtok()非常相似,但是它正确返回空字段。
  • @MartinR 可能。我正在使用带有 Linux 3.10.10 的 Fedora。
  • 所以这可能是一个替代方案。但即使这样也无法正确处理 aaa;bbb;"ddd;eee";fff 等引用文本中的分隔符。
  • @MartinR 幸运的是我现在不需要这个功能。我会尝试使用strsep()
  • 您使用哪种编程语言?您可以将其包含在您的标题中。

标签: c csv strtok


【解决方案1】:

如果可用,一个可能的替代方法是使用 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);

输出:

令牌=值 令牌= 令牌=测试 令牌=等

因此正确处理空字段。

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

【讨论】:

  • 工作就像一个魅力。非常感谢!
【解决方案2】:

没有办法让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 或测试的情况下编写,可能是一个无效的实现,但这个想法是成立的)。

【讨论】:

  • 听起来不错。我要试试这个方法。
  • 我会感谢 cmets 关于downvotes,如果有什么问题,我想更正这个实现。
【解决方案3】:

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

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

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

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

【讨论】:

  • 到目前为止,我一直试图避免编写自己的解析函数。
  • 嗯,避免这种情况实际上是个好主意。有这个库,在另一个 StackOverflow 线程中推荐:sourceforge.net/projects/libcsv
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-04
  • 1970-01-01
  • 1970-01-01
  • 2011-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多