2017-08-21 48 views
4

我想用Matlab的fscanf函数读取包含在小配置文件中的信息。该文件的内容是;fscanf函数的奇怪行为

YAcex: 1.000000 
YOx: 1.000000 
KAce: 1.000000 

用于解析文件的matlab代码是;

fh = fopen('parameters', 'r'); 
fscanf(fh, 'YAcex: %f\n') 
fscanf(fh, 'YOx: %f\n') 
fscanf(fh, 'KAce: %f\n') 
fclose(fh); 

当调用此脚本时,只有“YAcex”行被正确读取; fscanf为其他两行返回[]。如果YOx和KAce行被切换(YOx之前的KAce),则fscanf会正确读取所有行。

有人可以解释这种行为吗?

补充信息:输入文件中的换行符是简单的换行符(\ n字符,不含\ r字符)。

回答

8

你的问题是,你只需要在每次调用一个值读取到fscanf,但默认情况下它尝试读取尽可能多的价值成为可能。请注意,此摘录从文档:

fscanf函数重新应用在整个文件的格式,并在最终的文件标记位置的文件指针。如果fscanf无法比拟formatSpec到的数据,仅读取匹配并停止处理的部分。

这意味着第一次调用正确读取该文件的第一行,但随后尝试读取下一行也,发现没有确切的匹配format specifier。它找到一个局部匹配为下一行,其中的YOx:第一YYAcex:开头匹配的格式说明。这部分匹配将文件指针直接放置在之后YYOx:中,导致下一次调用fscanf失败,因为它在Ox: ...处开始。我们可以ftell说明这一点:

fh = fopen('parameters', 'r'); 
fscanf(fh, 'YAcex: %f\n'); 
ftell(fh) 

ans = 

    18 % The "O" is the 18th character in the file 

当你切换YOx:KAce:线,下一行的部分比赛没有发生任何更多,所以文件指针指向结束开始的下一行每一次和所有的阅读都是成功的。

那么,你怎么能解决这个问题?一种选择是始终指定size argument所以fscanf不重新格式说明不必要的:

fh = fopen('parameters', 'r'); 
fscanf(fh, 'YAcex: %f\n', 1); 
fscanf(fh, 'YOx: %f\n', 1); 
fscanf(fh, 'KAce: %f\n', 1); 
fclose(fh); 

另一种选择是做这一切在同一行:

fh = fopen('parameters', 'r'); 
values = fscanf(fh, 'YAcex: %f\n YOx: %f\n KAce: %f\n'); 
fclose(fh); 

而且values将是一个3包含文件中3个值的逐个数组。

+0

根据OP,当YOx和KAce线路切换时,他的代码可以正确读取。对此有何看法? –

+0

我似乎无法在2014b上重现此行为@Sarder Usama – BillBokeey

+0

尝试在文本文件和MATLAB脚本中切换这些行。 https://i.stack.imgur.com/Azdmh.jpg –

1

正如您已经认识到的那样,\ r或\ r \ n可能导致这种行为。可能的原因与此类似,例如,某处有一些不可见的字符,如空间。您可以通过阅读所有的UINT8调试这一点,并在发生问题时,看看位置:

u8 = fread(fh, inf, '*uint8')'; 

一个笨的办法来避免这种问题是阅读所有的字符,搜索每个关键字:

fh = fopen('parameters'); 
ch = fread(fh, inf, '*char')'; % read all as char 
fclose(fh); 

YAcex = regexp(ch, '(?<=YAcex:\s?)[\d\.]+', 'match', 'once'); % parse YAcex 

您可以相应地解析其他人。这样做的好处是它对某个地方的空间不太敏感,参数的顺序并不重要。

+1

虽然这只是一个小文件的整洁解决方案,但反复使用正则表达式为关键字添加大文件是解决方案的一种缓慢方式,无论如何您都知道它们在单独的行上! – Wolfie

+0

@Wolfie非常真实。另一个答案是完美的IMO。如果您觉得合适,我会删除我的答案。 –

+0

对你来说,你的解决方案是有效的,它可能不是这个问题的最佳解决方案:) – Wolfie