我有一个多行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);
这并不像我希望的那样有效,而且我在缩小错误方面遇到了麻烦。有谁知道我怎么能正确阅读这些内容?
答案 0 :(得分:3)
我主要赞同Pablo(scanf
家庭不能做出很好的解析器),但是值得了解如何编写scanf
模式。您正在寻找的模式是这样的:
fscanf(" %*[^\t] %128[^\t] %*[^\t] %128[^\n]", name_string, desc_string)
注意:
%[xyz]
是一个指令。 %[xyz]s
是两个指令,第二个与文字s
匹配
据我所知,没有办法匹配单个文字制表符,因为模式中的任何空格都与输入中的任何数量的空格(包括无)相匹配。我在我的示例中使用了一个空格,它将匹配终止选项卡,但它也会匹配任意数量的连续选项卡,因此无法正确解析空字段。
128个字符的限制不包括终止NUL字符。
此外,如果扫描因超出字符限制而停止,则不会自动跳过字段的其余部分,因此您最终会与输入不同步。
更好的模式是:
fscanf(" %*[^\t] %128[^\t]%*[^\t] %*[^\t] %128[^\n]%*[^\n]", name_string, desc_string)
如果需要,显式跳过字段中的剩余字符。更好的解决方案是使用a
修饰符并为您获取fscanf
到malloc
内存。
答案 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
终止。