2

我有一个具有以下格式的多行 TSV 文件:

Type\tBasic Name\tAttribute\tA Long Description\n

如您所见,基本名称和描述都可以包含一些空格。我正在尝试读取每一行并提取元素。现在,我已将其范围缩小到仅提取基本名称。我的 fscanf 如下:

fscanf(file_in, "%*[^ ]s\t%128[^ ]s\t%*[^ ]s\t%[^ ]s\n", name_string, desc_string);

这不像我希望的那样起作用,而且我在缩小错误范围时遇到了麻烦。有谁知道我如何正确阅读这些行?

4

3 回答 3

3

我大多同意 Pablo 的观点(这个scanf家族并不擅长解析器),但了解如何编写scanf模式是值得的。您正在寻找的模式是这样的:

fscanf(" %*[^\t] %128[^\t] %*[^\t] %128[^\n]", name_string, desc_string)

笔记:

  1. %[xyz]是一个指令。%[xyz]s是两个指令,其中第二个与文字匹配s

  2. 据我所知,没有办法匹配单个文字制表符,因为模式中的任何空格都匹配输入中任何数量的空格(包括无空格)。我在示例中使用了一个空格,它将匹配一个终止选项卡,但它也将匹配任意数量的连续选项卡,因此无法正确解析空字段。

  3. 128 个字符的限制不包括终止 NUL 字符。

  4. 此外,如果扫描因超出字符限制而停止,它不会自动跳过该字段的其余部分,因此您最终会与输入不同步。

更好的模式是:

fscanf(" %*[^\t] %128[^\t]%*[^\t] %*[^\t] %128[^\n]%*[^\n]", name_string, desc_string)

如有必要,它会显式跳过字段中的剩余字符。更好的解决方案是使用a修饰符并为您获取fscanf内存malloc

于 2012-10-10T23:47:48.470 回答
2

我宁愿用strtok这个。它比fscanf这个函数系列只在格式 100% OK 时才有效,否则你最终会丢失值。

看看Parallel to PHP's "explode" in C: Split char* into char* using delimiter,我在这里更详细地解释了如何使用strtok.

所以,阅读每一行fgets并用strtok.

于 2012-10-10T23:39:09.547 回答
0

首先,正如已经指出的那样,the%[]本身就是一个转换说明符。后面没有s[]。您在格式字符串中的s-es 不会被视为转换说明符的一部分。你必须摆脱那些s-es。

其次,正如您自己所说,您的文件是 TAB 分隔的。这立即意味着您应该使用%[^\t]转换说明符(或%[^\n]最后一部分的说明符)来提取序列的连续部分。你为什么使用%[^ ]它,你期望它如何工作?实际上在空格字符处停止解析,这%[^ ]与您想要的相反。

在您的示例中,说明符的正确组合将是

fscanf(file_in, "%*[^\t]\t%128[^\t]\t%*[^\t]\t%[^\n]\n", name_string, desc_string);

此格式字符串假定字符串的所有 4 部分都保证存在,并且最后一部分保证以\n.

于 2012-10-10T23:59:37.517 回答