2008-11-05 102 views
23

我一直試圖使用SPACE作爲分隔符來標記字符串,但它不起作用。有沒有人建議它爲什麼不起作用?令牌化字符串C

編輯:標記化而使用:

strtok(string, " "); 

的代碼是類似如下

pch = strtok (str," "); 
while (pch != NULL) 
{ 
    printf ("%s\n",pch); 
    pch = strtok (NULL, " "); 
} 
+0

您的示例將獲得第一個標記,請查看gbjbaanb或我的答案,以瞭解正確的用法。 – 2008-11-05 20:02:20

+0

好的。現在我們正在某個地方。你認爲你沒有得到什麼樣的行爲? – dmckee 2008-11-05 20:08:22

+0

你的代碼是正確的,請讓我們知道你的輸入字符串和結果是什麼。 – 2008-11-05 20:08:46

回答

0

當讀strtok的文檔,我看你需要一個NULL指針傳遞後的第一個「初始化「打電話。也許你沒有那樣做。只是猜測當然。

38

做這樣的:

char s[256]; 
strcpy(s, "one two three"); 
char* token = strtok(s, " "); 
while (token) { 
    printf("token: %s\n", token); 
    token = strtok(NULL, " "); 
} 

注:strtok修改字符串的tokenising,所以它不可能是一個const char*

32

這裏的strtok使用的例子,請記住,strtok是破壞性的,它的輸入字符串的(因此不能永遠可以在一個字符串常量

char *p = strtok(str, " "); 
while(p != NULL) { 
    printf("%s\n", p); 
    p = strtok(NULL, " "); 
} 

基本上要注意的是使用這傳遞一個NULLstrtok第一個參數告訴它要得到它以前的標記化字符串的下一個標記。

3

可以通過引入一個額外的變量來簡化代碼。

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

int main() 
{ 
    char str[100], *s = str, *t = NULL; 

    strcpy(str, "a space delimited string"); 
    while ((t = strtok(s, " ")) != NULL) { 
     s = NULL; 
     printf(":%s:\n", t); 
    } 
    return 0; 
} 
6

的strtok是非常危險的。它不是線程安全的。它的用途是在一個循環中反覆調用,傳遞前一個調用的輸出。 strtok函數有一個內部變量,用於存儲strtok調用的狀態。這種狀態並不是每個線程都獨有的 - 它是全球性的。如果其他代碼在另一個線程中使用strtok,則會出現問題。不是你想跟蹤的那種問題!

我建議你找一個正則表達式的實現,或者使用sscanf會拉開字符串。

試試這個:

char strprint[256]; 
char text[256]; 
strcpy(text, "My string to test"); 
while (sscanf(text, "%s %s", strprint, text) > 0) { 
    printf("token: %s\n", strprint); 
} 

注:因爲它的分離 '文本' 的字符串被破壞。這可能不是優選的行爲=)

2

我爲了分裂值所做的一些字符串的功能,通過使用較少的指針,因爲我可以因爲這個代碼是旨在對PIC18F處理器上運行。這些處理器不處理的指針真的很好,當你有幾個可用的可用RAM:

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

char POSTREQ[255] = "pwd=123456&apply=Apply&d1=88&d2=100&pwr=1&mpx=Internal&stmo=Stereo&proc=Processor&cmp=Compressor&ip1=192&ip2=168&ip3=10&ip4=131&gw1=192&gw2=168&gw3=10&gw4=192&pt=80&lic=&A=A"; 

int findchar(char *string, int Start, char C) { 
    while((string[Start] != 0)) { Start++; if(string[Start] == C) return Start; } 
    return -1; 
} 

int findcharn(char *string, int Times, char C) { 
    int i = 0, pos = 0, fnd = 0; 

    while(i < Times) { 
     fnd = findchar(string, pos, C); 
     if(fnd < 0) return -1; 
     if(fnd > 0) pos = fnd; 
     i++; 
    } 
    return fnd; 
} 

void mid(char *in, char *out, int start, int end) { 
    int i = 0; 
    int size = end - start; 

    for(i = 0; i < size; i++){ 
     out[i] = in[start + i + 1]; 
    } 
    out[size] = 0; 
} 

void getvalue(char *out, int index) { 
    mid(POSTREQ, out, findcharn(POSTREQ, index, '='), (findcharn(POSTREQ, index, '&') - 1)); 
} 

void main() { 
    char n_pwd[7]; 
    char n_d1[7]; 

    getvalue(n_d1, 1); 

    printf("Value: %s\n", n_d1); 
} 
-1
int not_in_delimiter(char c, char *delim){ 

    while(*delim != '\0'){ 
      if(c == *delim) return 0; 
      delim++; 
    } 
    return 1; 
} 

char *token_separater(char *source, char *delimiter, char **last){ 

char *begin, *next_token; 
char *sbegin; 

/*Get the start of the token */ 
if(source) 
    begin = source; 
else 
    begin = *last; 

sbegin = begin; 

/*Scan through the string till we find character in delimiter. */ 
while(*begin != '\0' && not_in_delimiter(*begin, delimiter)){ 
     begin++; 
} 

/* Check if we have reached at of the string */ 
if(*begin == '\0') { 
/* We dont need to come further, hence return NULL*/ 
    *last = NULL; 
    return sbegin; 
} 
/* Scan the string till we find a character which is not in delimiter */ 
next_token = begin; 
while(next_token != '\0' && !not_in_delimiter(*next_token, delimiter)) { 
    next_token++; 
} 
/* If we have not reached at the end of the string */ 
if(*next_token != '\0'){ 
    *last = next_token--; 
    *next_token = '\0'; 
    return sbegin; 
} 
} 

void main(){ 

    char string[10] = "abcb_dccc"; 
    char delim[10] = "_"; 
    char *token = NULL; 
    char *last = "" ; 
    token = token_separater(string, delim, &last); 
    printf("%s\n", token); 
    while(last){ 
      token = token_separater(NULL, delim, &last); 
      printf("%s\n", token); 
    } 

}

你可以在博客中我的個人資料:)

0

這裏提到閱讀詳細分析是另一個strtok()實現,它具有識別連續分隔符的能力(標準庫的strtok()沒有這個)

該函數是BSD許可字符串庫的一部分,稱爲zString。你比歡迎更多的貢獻:)

https://github.com/fnoyanisi/zString

char *zstring_strtok(char *str, const char *delim) { 
    static char *static_str=0;  /* var to store last address */ 
    int index=0, strlength=0;  /* integers for indexes */ 
    int found = 0;     /* check if delim is found */ 

    /* delimiter cannot be NULL 
    * if no more char left, return NULL as well 
    */ 
    if (delim==0 || (str == 0 && static_str == 0)) 
     return 0; 

    if (str == 0) 
     str = static_str; 

    /* get length of string */ 
    while(str[strlength]) 
     strlength++; 

    /* find the first occurance of delim */ 
    for (index=0;index<strlength;index++) 
     if (str[index]==delim[0]) { 
      found=1; 
      break; 
     } 

    /* if delim is not contained in str, return str */ 
    if (!found) { 
     static_str = 0; 
     return str; 
    } 

    /* check for consecutive delimiters 
    *if first char is delim, return delim 
    */ 
    if (str[0]==delim[0]) { 
     static_str = (str + 1); 
     return (char *)delim; 
    } 

    /* terminate the string 
    * this assignmetn requires char[], so str has to 
    * be char[] rather than *char 
    */ 
    str[index] = '\0'; 

    /* save the rest of the string */ 
    if ((str + index + 1)!=0) 
     static_str = (str + index + 1); 
    else 
     static_str = 0; 

     return str; 
} 

正如在先前的文章中提到,因爲strtok(),或一個我上面implmented,依靠static *char變量保存之間的最後一個分隔符的位置在處理多線程應用程序時應該格外小心。