我有一个固定宽度列的文件,它是2到4位整数,一些浮点数和字符串的混合。全部混合在一起。结果是一个在页面上运行的scanf格式......
fscanf(file, "%2d%2d%2d%2d%4d%4d%4d%1s%1d%4d%1s%1d%4d%1s%1d%4d%1s%1d%4d%1s%1d%4d%1s%1d%4d%1s%1d%2d%1s%1d%2d%1s%1d%4d%1s%1d%4d%1s%1d%3d%1s%1d%4d%1s%1d%3d%1s%1d%3d%1s%1d%4d%1s%1d%5ld%1s%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%3d%1s%1d%3d%1s%1d%3d%1s%1d%2d%1s%1d",
这甚至不包括变量列表!
有关如何使其可维护的建议?我应该连续几次scanf
吗?或者在这种情况下人们使用的是规范解决方案吗?
更新:我在第一篇文章中包含了原始数据,但在编辑过程中显然已将其删除。有问题的数据称为TMY2,您可以找到定义和示例格式字符串here。还有一种新的格式TMY3,它使用CVS,所以我有很多很好的例子来解析它。
答案 0 :(得分:3)
具有固定宽度列的混合文件.... 如何使这个可维护?
步骤1,将行读入fgets()
的宽大缓冲区。请勿使用fscanf()
@Andrew Henle
#define MY_BUF_N 400
char buf[MY_BUF_N * 2]; // make buffer 2x aticipated max size
if (fgets(buf, sizeof buf, file) == NULL) {
Handle_EOF_or_Error();
}
根据重复模式识别群组:
#define FMT_PRE "%2d%2d%2d%2d%4d%4d"
#define FMT_5 "%4ld%1s%1d"
#define FMT_4 "%4d%1s%1d"
#define FMT_3 "%4d%1s%1d"
#define FMT_2 "%4d%1s%1d"
#define FMT_MID "%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d"
使用字符串文字连接。 @jxh
#define FMT_ALL FMT_PRE \
FMT_4 FMT_4 FMT_4 FMT_4 FMT_4 FMT_4 \
FMT_2 FMT_2 FMT_4 FMT_4 FMT_3 FMT_4 \
FMT_4 FMT_4 FMT_3 FMT_3 FMT_4 FMT_5 \
FMT_MID \
FMT_3 FMT_3 FMT_3 FMT_2
使用" %n"
测试整个扫描是否成功
int n = 0;
sscanf(FMT_ALL " %n", ...
...
... /* variable list laid out like the format statements. */
...
&n);
测试n
// Did scan reach the end?
if (n == 0) {
Handle_incomplete_scan();
}
// Was there any remaining junk?
if (buf[n] != '\0') {
Handle_junk_at_the_end();
}
添加其他测试以验证对象是否在范围内。
一般来说,我会重写。 @PeterJ_01在使用fgets()
的第1步之后,使用strtol()
等的帮助函数按顺序解析数据。
size_t i = 0; // Index in buffer
if (parse_int(&object1, buf, &i, min_value, max_value)) error();
if (parse_int(&object1, buf, &i, min_value, max_value)) error();
...
if (parse_string(object7, sizeof object7, buf, &i)) error();
....
if (parse_long(&object12, buf, &i, min_value, max_value)) error();
...
答案 1 :(得分:1)
最好的选择是:
希望有所帮助:)
答案 2 :(得分:0)
鉴于您正在http://rredc.nrel.gov/solar/pubs/tmy2/tab3-2.html处理文档中的指定数据,您根本无法安全使用RR.test();
。
因为"规范"被打破。厉害。它没有规定如何在每个字段中放置数据。数据可以用尾随空格左对齐,用前导空格右对齐,用前导零右对齐。
所有这些都适合"规范"。并且没有办法编写一个可以处理所有这些可能性的scanf()
格式字符串。
直言不讳,无论是谁写了#34;规范"是无能的。
如果使用类似scanf()
和C格式字符串的方式编写数据:
sprintf()
无法使用(%2d%2d%2d%2d%4d%4d%4d%1s%1d%4d%1s%1d%4d%1s%1d%4d%1s%1d%4d%1s%1d%4d%1s
%1d%4d%1s%1d%2d%1s%1d%2d%1s%1d%4d%1s%1d%4d%1s%1d%3d%1s%1d%4d%1s%1d%3d
%1s%1d%3d%1s%1d%4d%1s%1d%5ld%1s%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%3d%1s
%1d%3d%1s%1d%3d%1s%1d%2d%1s%1d)
安全地阅读。例如,此代码:
scanf()
生成此输出:
#include <stdio.h>
int main( int argc, char **argv )
{
int a = 1;
int b = 99;
int c = 34;
char buffer[ 128 ];
sprintf( buffer, "%2d%2d%2d", a, b, c );
printf( "a: %d\nb: %d\nc: %d\n", a, b, c );
printf( "String: '%s'\n", buffer );
sscanf( buffer, "%2d%2d%2d", &a, &b, &c );
printf( "a: %d\nb: %d\nc: %d\n", a, b, c );
return( 0 );
}
请注意,这些值不匹配。
再次说明:您无法对该数据使用a: 1
b: 99
c: 34
String: ' 19934'
a: 19
b: 93
c: 4
。完全没有。