2017-08-21 50 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