强制fscanf消耗可能的空白

时间:2012-10-10 23:00:12

标签: c whitespace string-formatting scanf

我有一个多行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);

这并不像我希望的那样有效,而且我在缩小错误方面遇到了麻烦。有谁知道我怎么能正确阅读这些内容?

3 个答案:

答案 0 :(得分: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. 此外,如果扫描因超出字符限制而停止,则不会自动跳过字段的其余部分,因此您最终会与输入不同步。

  5. 更好的模式是:

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

    显式跳过字段中的剩余字符。更好的解决方案是使用a修饰符并为您获取fscanfmalloc内存。

答案 1 :(得分:2)

我宁愿使用strtok。它比fscanf更精确,因为此功能系列仅在格式为100%正常时才起作用,否则您最终会丢失值。

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

因此,请使用fgets阅读每一行并使用strtok解析。

答案 2 :(得分:0)

首先,正如已经指出的那样,%[]本身就是一个转换说明符。 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终止。