2014-05-23 96 views
0

我有以下問題: sscanf沒有回來時,我希望它的方式。 這是sscanfsscanf的不返回我想要

sscanf(naru, 
     "%s[^;]%s[^;]%s[^;]%s[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]" 
     "%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]" 
     "%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]", 
     &jokeri, &paiva1, &keskilampo1, &minlampo1, &maxlampo1, 
     &paiva2, &keskilampo2, &minlampo2, &maxlampo2, &paiva3, 
     &keskilampo3, &minlampo3, &maxlampo3, &paiva4, &keskilampo4, 
     &minlampo4, &maxlampo4, &paiva5, &keskilampo5, &minlampo5, 
     &maxlampo5, &paiva6, &keskilampo6, &minlampo6, &maxlampo6, 
     &paiva7, &keskilampo7, &minlampo7, &maxlampo7); 

它掃描的字符串:

const char *str = "city;" 
        "2014-04-14;7.61;4.76;7.61;" 
        "2014-04-15;5.7;5.26;6.63;" 
        "2014-04-16;4.84;2.49;5.26;" 
        "2014-04-17;2.13;1.22;3.45;" 
        "2014-04-18;3;2.15;3.01;" 
        "2014-04-19;7.28;3.82;7.28;" 
        "2014-04-20;10.62;5.5;10.62;"; 

所有的變量都存儲爲char paiva1[22]等;但是,sscanf沒有正確存儲除城市之外的任何內容。我一直試圖停止每個變量;。 任何幫助如何得到它來存儲日期等正確的,將不勝感激。

或者,如果有這樣做更聰明的方式,我很開放的建議。

+4

'sscanf(naru,「%s [^;]%s [^;] ...' - >'sscanf(naru,」%[^;];%[^;]; ...' – BLUEPIXY

+0

你應該總是檢查任何scanf函數的返回值,而且,像這樣的長格式字符串將會成爲一個維護噩夢,如果它需要改變的話 – hyde

+1

Yeesh,只是分割';'並完成那麼 –

回答

2

存在多個問題,但BLUEPIXY碰到第一個—掃描集表示法不遵循%s

您格式的第一行是:

"%s[^;]%s[^;]%s[^;]%s[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]" 

因爲它的立場,它會尋找一個空格隔開的字,隨後[,一個^,一個;](這是自矛盾的;字符串之後的字符是空格或字符串的結尾)。

的第一個鏈接地址是正確地使用掃描臺:

"%[^;]%[^;]%[^;]%[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]" 

現在你有了第一%[^;]掃描所有內容串或第一個分號結束,留下的不是第二%[;]問題匹配。

"%[^;]; %[^;]; %[^;]; %[^;]; %f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]" 

這看起來一個字符串到一個分號,那麼分號,則可選空格,然後重複用於三個項目。除了添加一個長度來限制字符串的大小,防止溢出,這些都很好。 %f是好的。以下材料再次查找奇怪的字符序列。

然而,當看到數據時,它似乎是由一個城市組成的,然後是七組「一個日期加三個數字」。

你會用結構數組做的更好(如果你與那些還沒有工作),或一組4個並行陣列和循環:

char jokeri[30]; 
char paiva[7][30]; 
float keskilampo[7]; 
float minlampo[7]; 
float maxlampo[7]; 

int eoc; // End of conversion 
int offset = 0; 
char sep; 
if (fscanf(str + offset, "%29[^;]%c%n", jokeri, &sep, &eoc) != 2 || sep != ';') 
    ...report error... 
offset += eoc; 

for (int i = 0; i < 7; i++) 
{ 
    if (fscanf(str + offset, "%29[^;];%f;%f;%f%c%n", paiva[i], 
       &keskilampo[i], &minlampo[i], &maxlampo[i], &sep, &eoc) != 5 || 
     sep != ';') 
     ...report error... 
    offset += eoc; 
} 

How to use sscanf() in loops見。

現在你有一個可以管理的數據。這29個單獨命名的變量是一個可怕的想法;使用它們的代碼將是可怕的。

請注意,掃描設置轉換規範將字符串限制爲比jokeripaiva陣列元素的尺寸短一個的最大長度。


你可能合法地想知道爲什麼代碼使用%c%n&sep&eoc之前。有一個原因,但它很微妙。假設sscanf()格式字符串:

"%29[^;];%f;%f;%f;%n" 

此外,假設有一個在數據的問題,即第三個數字分號後失蹤。撥打sscanf()的電話會報告它已成功完成4次轉換,但不會將%n作爲轉讓進行計數,因此您無法分辨sscanf()未找到分號,因此根本沒有設置&eoc;該值從之前的調用sscanf()剩下,或者只是未初始化。通過使用%c將值掃描到sep,我們得到5個成功返回的結果,我們可以確定%n也是成功的。代碼檢查sep中的值實際上是分號而不是別的。

您可能要考慮在分號前和在%c之前的空格。他們將允許一些其他數據字符串被轉換,否則將不會被匹配。格式字符串中的空格(掃描集外部)表示可能出現空白的位置。

+0

非常感謝!似乎是處理大量變量的最明智的方式。 – pellerusty

1

我會用strtok功能,打破你的字符串轉換成使用;作爲分隔符碎片。這種長格式的字符串將來可能會成爲問題的根源。