2015-09-04 43 views
0

strtok_r在解析時將空字符放入輸入字符串的不同位置。原始字符串僅在strtok_r返回NULL後纔會恢復。strtok/strtok_r退出解析中間

如果我需要在靠近長字符串開頭的地方提取一個標記,該怎麼辦?如果我離開循環,輸入字符串保持中斷狀態。我可以嘗試手動恢復分隔符,但我不知道它是否是最後一個標記。 問題是saveptr值沒有記錄。

void extract_nth_token(char *res, size_t reslen, char *str, const char *delim, int n) { 
    int i; 
    char *token; 
    char *save_ptr; 

    token = strtok_r(str, delim, &save_ptr); 
    for(i = 0; token != NULL; i++) { 
    token = strtok_r(NULL, delim, &save_ptr); 
    if (i == n) { 
     snprintf(res, reslen, "%s", token); 
     /* token[strlen(token)] = delim[0]; */ 
     /* break; */ 
    } 
    } 
} 
+1

'的問題是,saveptr值沒有記錄。「你在尋找什麼樣的」價值「? –

+2

製作一個字符串的副本並使用它。 – Barmar

+0

@SouravGhosh告訴我它的值是否是最後一個標記 – basin

回答

2

的strtok()和strtok_r()是可怕的功能:

  • 他們修改輸入字符串
  • 他們將連續分隔符爲一體,它可以跳過空白時,可以預期的,但它是解析.CSV(或製表符分隔)輸入時不打算。

最好是完全避免strtok()和strtok_r(),並使用strspn()和strcspn()。下面的函數做到這一點。返回值與snprintf()類似:找到的標記中的字符數(不包括終止NUL字節)

  • 如果沒有標記#n:將'\ 0'寫入緩衝區和0返回
  • 如果緩衝區對於找到的標記加上終止的NUL字節太小,'\ 0'被寫入緩衝區並且令牌長度返回
  • 是緩衝區足夠大,將令牌+'\ 0'寫入它,並返回strlen(令牌)。

#include <stdio.h> 
#include <string.h> 

size_t extract_nth_token_ohne_strtok_r(char *res, size_t maxlen, const char *str, const char *delim, int n) 
{ 
size_t pos, len; 
int itok; 

for (itok=0,pos=0; str[pos];) { 
     len = strcspn(str+pos, delim); 
     if (itok++ == n) { 
       if (len < maxlen) memcpy(res, str+pos, len), res[len] = 0; 
       else res[0] = 0; 
       return len; 
       } 
     pos += len; 
     if (str[pos]) pos++; 
     } 
res[0] = 0; 
return 0; 
} 

int main(void) 
{ 
char * omg = "zero one\ttwo \tfour\nfive" ; 
char token[80]; 
size_t toklen; 
int ii; 

printf("\n## With a large enough buffer:\n"); 
for (ii=0; ii < 7; ii++) { 
     toklen = extract_nth_token_ohne_strtok_r(token, sizeof token 
       , omg, " \t\n", ii); 
     printf("%d: res=%zu \"%s\"\n" , ii, toklen, token); 
     } 

printf("\n## With 4-character buffer:\n"); 
for (ii=0; ii < 7; ii++) { 
     toklen = extract_nth_token_ohne_strtok_r(token, 4 
       , omg, " \t\n", ii); 
     printf("%d: res=%zu \"%s\"\n" , ii, toklen, token); 
     } 

return 0; 
} 

注意:如果你想將連續whitspace爲一體,你可以更換if (str[pos]) pos++;通過:

pos += strspn(str+pos, delim);