在C中用分隔符分割string

我如何编写一个函数来分割和返回一个数组的string与分隔符在C编程语言?

char* str = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC"; str_split(str,','); 

您可以使用strtok()函数来分割一个string(并指定要使用的分隔符)。 请注意, strtok()将修改传递给它的string。 如果原始string需要在其他地方复制一份并传递给strtok()

编辑:

例子(注意它不处理连续的分隔符,例如“JAN ,,, FEB,MAR”):

 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> char** str_split(char* a_str, const char a_delim) { char** result = 0; size_t count = 0; char* tmp = a_str; char* last_comma = 0; char delim[2]; delim[0] = a_delim; delim[1] = 0; /* Count how many elements will be extracted. */ while (*tmp) { if (a_delim == *tmp) { count++; last_comma = tmp; } tmp++; } /* Add space for trailing token. */ count += last_comma < (a_str + strlen(a_str) - 1); /* Add space for terminating null string so caller knows where the list of returned strings ends. */ count++; result = malloc(sizeof(char*) * count); if (result) { size_t idx = 0; char* token = strtok(a_str, delim); while (token) { assert(idx < count); *(result + idx++) = strdup(token); token = strtok(0, delim); } assert(idx == count - 1); *(result + idx) = 0; } return result; } int main() { char months[] = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC"; char** tokens; printf("months=[%s]\n\n", months); tokens = str_split(months, ','); if (tokens) { int i; for (i = 0; *(tokens + i); i++) { printf("month=[%s]\n", *(tokens + i)); free(*(tokens + i)); } printf("\n"); free(tokens); } return 0; } 

输出:

 $ ./main.exe months=[JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC] month=[JAN] month=[FEB] month=[MAR] month=[APR] month=[MAY] month=[JUN] month=[JUL] month=[AUG] month=[SEP] month=[OCT] month=[NOV] month=[DEC] 

我认为strsep仍然是最好的工具:

 while ((token = strsep(&str, ","))) my_fn(token); 

这实际上是分割一个string的一行。

额外的括号是表示我们有意testing赋值结果而不是相等运算符==的风格元素。

为了使这个模式起作用, tokenstr都有typeschar * 。 如果你开始使用string,那么你首先要创build它的副本:

 // More general pattern: const char *my_str_literal = "JAN,FEB,MAR"; char *token, *str, *tofree; tofree = str = strdup(my_str_literal); // We own str's memory now. while ((token = strsep(&str, ","))) my_fn(token); free(tofree); 

如果两个分隔符在str一起出现,您将得到一个空string的token值。 str的值被修改,因为遇到的每个分隔符都被一个零字节覆盖 – 这是复制首先被parsing的string的另一个好理由。

在评论中,有人build议strtokstrsep更好,因为strtok更便于携带。 Ubuntu和Mac OS X strsep ; 猜测其他unixy系统也是如此。 Windows缺lessstrsep ,但是它具有strbrk ,可以实现这个短而甜的strsepreplace:

 char *strsep(char **stringp, const char *delim) { if (*stringp == NULL) { return NULL; } char *token_start = *stringp; *stringp = strpbrk(token_start, delim); if (*stringp) { **stringp = '\0'; (*stringp)++; } return token_start; } 

这里是strsep vs strtok一个很好的解释。 利弊可能主观判断; 不过,我认为这是一个明显的迹象, strsep被devise为strtok的替代品。

stringtokenizer这个代码应该把你放在正确的方向。

 int main(void) { char st[] ="Where there is will, there is a way."; char *ch; ch = strtok(st, " "); while (ch != NULL) { printf("%s\n", ch); ch = strtok(NULL, " ,"); } getch(); return 0; } 

下面的方法将为你做所有的工作(内存分配,计算长度)。 更多的信息和描述可以在这里find – 实现Java String.split()方法来拆分Cstring

 int split (const char *str, char c, char ***arr) { int count = 1; int token_len = 1; int i = 0; char *p; char *t; p = str; while (*p != '\0') { if (*p == c) count++; p++; } *arr = (char**) malloc(sizeof(char*) * count); if (*arr == NULL) exit(1); p = str; while (*p != '\0') { if (*p == c) { (*arr)[i] = (char*) malloc( sizeof(char) * token_len ); if ((*arr)[i] == NULL) exit(1); token_len = 0; i++; } p++; token_len++; } (*arr)[i] = (char*) malloc( sizeof(char) * token_len ); if ((*arr)[i] == NULL) exit(1); i = 0; p = str; t = ((*arr)[i]); while (*p != '\0') { if (*p != c && *p != '\0') { *t = *p; t++; } else { *t = '\0'; i++; t = ((*arr)[i]); } p++; } return count; } 

如何使用它:

 int main (int argc, char ** argv) { int i; char *s = "Hello, this is a test module for the string splitting."; int c = 0; char **arr = NULL; c = split(s, ' ', &arr); printf("found %d tokens.\n", c); for (i = 0; i < c; i++) printf("string #%d: %s\n", i, arr[i]); return 0; } 

在上面的例子中,将有一种方法来返回一个null结尾的string数组(像你想要的)在string中的地方。 它不会传递一个string,因为它必须被函数修改:

 #include <stdlib.h> #include <stdio.h> #include <string.h> char** str_split( char* str, char delim, int* numSplits ) { char** ret; int retLen; char* c; if ( ( str == NULL ) || ( delim == '\0' ) ) { /* Either of those will cause problems */ ret = NULL; retLen = -1; } else { retLen = 0; c = str; /* Pre-calculate number of elements */ do { if ( *c == delim ) { retLen++; } c++; } while ( *c != '\0' ); ret = malloc( ( retLen + 1 ) * sizeof( *ret ) ); ret[retLen] = NULL; c = str; retLen = 1; ret[0] = str; do { if ( *c == delim ) { ret[retLen++] = &c[1]; *c = '\0'; } c++; } while ( *c != '\0' ); } if ( numSplits != NULL ) { *numSplits = retLen; } return ret; } int main( int argc, char* argv[] ) { const char* str = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC"; char* strCpy; char** split; int num; int i; strCpy = malloc( strlen( str ) * sizeof( *strCpy ) ); strcpy( strCpy, str ); split = str_split( strCpy, ',', &num ); if ( split == NULL ) { puts( "str_split returned NULL" ); } else { printf( "%i Results: \n", num ); for ( i = 0; i < num; i++ ) { puts( split[i] ); } } free( split ); free( strCpy ); return 0; } 

可能有一个更好的方法来做到这一点,但你明白了。

 #include <string.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> /** * splits str on delim and dynamically allocates an array of pointers. * * On error -1 is returned, check errno * On success size of array is returned, which may be 0 on an empty string * or 1 if no delim was found. * * You could rewrite this to return the char ** array instead and upon NULL * know it's an allocation problem but I did the triple array here. Note that * upon the hitting two delim's in a row "foo,,bar" the array would be: * { "foo", NULL, "bar" } * * You need to define the semantics of a trailing delim Like "foo," is that a * 2 count array or an array of one? I choose the two count with the second entry * set to NULL since it's valueless. * Modifies str so make a copy if this is a problem */ int split( char * str, char delim, char ***array, int *length ) { char *p; char **res; int count=0; int k=0; p = str; // Count occurance of delim in string while( (p=strchr(p,delim)) != NULL ) { *p = 0; // Null terminate the deliminator. p++; // Skip past our new null count++; } // allocate dynamic array res = calloc( 1, count * sizeof(char *)); if( !res ) return -1; p = str; for( k=0; k<count; k++ ){ if( *p ) res[k] = p; // Copy start of string p = strchr(p, 0 ); // Look for next null p++; // Start of next string } *array = res; *length = count; return 0; } char str[] = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC,"; int main() { char **res; int k=0; int count =0; int rc; rc = split( str, ',', &res, &count ); if( rc ) { printf("Error: %s errno: %d \n", strerror(errno), errno); } printf("count: %d\n", count ); for( k=0; k<count; k++ ) { printf("str: %s\n", res[k]); } free(res ); return 0; } 

尝试使用这个。

 char** strsplit(char* str, const char* delim){ char** res = NULL; char* part; int i = 0; char* aux = strdup(str); part = strdup(strtok(aux, delim)); while(part){ res = (char**)realloc(res, (i + 1) * sizeof(char*)); *(res + i) = strdup(part); part = strdup(strtok(NULL, delim)); i++; } res = (char**)realloc(res, i * sizeof(char*)); *(res + i) = NULL; return res; } 

以下是我的zString库的 strtok()实现。 zstring_strtok()与标准库的strtok()在处理连续分隔符方面有所不同。

只要看看下面的代码,确定你会得到一个关于它是如何工作的想法(我尽量使用尽可能多的评论)

 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; } 

下面是一个示例用法…

  Example Usage char str[] = "A,B,,,C"; printf("1 %s\n",zstring_strtok(s,",")); printf("2 %s\n",zstring_strtok(NULL,",")); printf("3 %s\n",zstring_strtok(NULL,",")); printf("4 %s\n",zstring_strtok(NULL,",")); printf("5 %s\n",zstring_strtok(NULL,",")); printf("6 %s\n",zstring_strtok(NULL,",")); Example Output 1 A 2 B 3 , 4 , 5 C 6 (null) 

该库可以从Github https://github.com/fnoyanisi/zString下载;

没有经过testing,可能是错误的,但应该给你一个良好的开端,应该如何工作:

 *char[] str_split(char* str, char delim) { int begin = 0; int end = 0; int j = 0; int i = 0; char *buf[NUM]; while (i < strlen(str)) { if(*str == delim) { buf[j] = malloc(sizeof(char) * (end-begin)); strncpy(buf[j], *(str + begin), (end-begin)); begin = end; j++; } end++; i++; } return buf; } 

这个函数接受一个char *string,并通过分隔符来分割它。 连续可以有多个分隔符。 请注意,该函数修改了orignalstring。 如果您需要原稿保持不变,您必须先复印原始string。 这个函数不会使用任何的cstring函数调用,所以它可能比别人快一点。 如果你不关心内存分配,你可以在函数的顶部分配大小为strlen(src_str)/ 2的子string(和前面提到的c ++“版本”一样)跳过函数的下半部分。 如果这样做,函数减less到O(N),但下面显示的内存优化方式是O(2N)。

function:

 char** str_split(char *src_str, const char deliminator, size_t &num_sub_str){ //replace deliminator's with zeros and count how many //sub strings with length >= 1 exist num_sub_str = 0; char *src_str_tmp = src_str; bool found_delim = true; while(*src_str_tmp){ if(*src_str_tmp == deliminator){ *src_str_tmp = 0; found_delim = true; } else if(found_delim){ //found first character of a new string num_sub_str++; found_delim = false; //sub_str_vec.push_back(src_str_tmp); //for c++ } src_str_tmp++; } printf("Start - found %d sub strings\n", num_sub_str); if(num_sub_str <= 0){ printf("str_split() - no substrings were found\n"); return(0); } //if you want to use a c++ vector and push onto it, the rest of this function //can be omitted (obviously modifying input parameters to take a vector, etc) char **sub_strings = (char **)malloc( (sizeof(char*) * num_sub_str) + 1); const char *src_str_terminator = src_str_tmp; src_str_tmp = src_str; bool found_null = true; size_t idx = 0; while(src_str_tmp < src_str_terminator){ if(!*src_str_tmp) //found a NULL found_null = true; else if(found_null){ sub_strings[idx++] = src_str_tmp; //printf("sub_string_%d: [%s]\n", idx-1, sub_strings[idx-1]); found_null = false; } src_str_tmp++; } sub_strings[num_sub_str] = NULL; return(sub_strings); } 

如何使用它:

  char months[] = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC"; char *str = strdup(months); size_t num_sub_str; char **sub_strings = str_split(str, ',', num_sub_str); char *endptr; if(sub_strings){ for(int i = 0; sub_strings[i]; i++) printf("[%s]\n", sub_strings[i]); } free(sub_strings); free(str); 

我的方法是扫描string,并让指针指向除字符(和第一个字符)后面的每个字符,同时将string中的分隔符的外观赋值为“\ 0”。
首先制作原始string的副本(因为它是常量),然后通过扫描得到分割的数量,将它传递给指针参数len 。 之后,将第一个结果指针指向复制string指针,然后扫描复制string:遇到一个分隔符,将其分配给'\ 0',从而结束前一个结果string,并将下一个结果string指针指向下一个字符指针。

 char** split(char* a_str, const char a_delim, int* len){ char* s = (char*)malloc(sizeof(char) * strlen(a_str)); strcpy(s, a_str); char* tmp = a_str; int count = 0; while (*tmp != '\0'){ if (*tmp == a_delim) count += 1; tmp += 1; } *len = count; char** results = (char**)malloc(count * sizeof(char*)); results[0] = s; int i = 1; while (*s!='\0'){ if (*s == a_delim){ *s = '\0'; s += 1; results[i++] = s; } else s += 1; } return results; } 

此优化方法在*结果中创build(或更新现有的)指针数组并返回* count中的元素数。

使用“max”来表示您期望的最大string数量(当您指定一个现有的数组或其他任何reaseon时),否则将其设置为0

要与分隔符列表进行比较,请将delim定义为char *并replace该行:

 if (str[i]==delim) { 

有以下两行:

  char *c=delim; while(*c && *c!=str[i]) c++; if (*c) { 

请享用

 #include <stdlib.h> #include <string.h> char **split(char *str, size_t len, char delim, char ***result, unsigned long *count, unsigned long max) { size_t i; char **_result; // there is at least one string returned *count=1; _result= *result; // when the result array is specified, fill it during the first pass if (_result) { _result[0]=str; } // scan the string for delimiter, up to specified length for (i=0; i<len; ++i) { // to compare against a list of delimiters, // define delim as a string and replace // the next line: // if (str[i]==delim) { // // with the two following lines: // char *c=delim; while(*c && *c!=str[i]) c++; // if (*c) { // if (str[i]==delim) { // replace delimiter with zero str[i]=0; // when result array is specified, fill it during the first pass if (_result) { _result[*count]=str+i+1; } // increment count for each separator found ++(*count); // if max is specified, dont go further if (max && *count==max) { break; } } } // when result array is specified, we are done here if (_result) { return _result; } // else allocate memory for result // and fill the result array *result=malloc((*count)*sizeof(char*)); if (!*result) { return NULL; } _result=*result; // add first string to result _result[0]=str; // if theres more strings for (i=1; i<*count; ++i) { // find next string while(*str) ++str; ++str; // add next string to result _result[i]=str; } return _result; } 

用法示例:

 #include <stdio.h> int main(int argc, char **argv) { char *str="JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC"; char **result=malloc(6*sizeof(char*)); char **result2=0; unsigned long count; unsigned long count2; unsigned long i; split(strdup(str),strlen(str),',',&result,&count,6); split(strdup(str),strlen(str),',',&result2,&count2,0); if (result) for (i=0; i<count; ++i) { printf("%s\n",result[i]); } printf("\n"); if (result2) for (i=0; i<count2; ++i) { printf("%s\n", result2[i]); } return 0; } 

我的代码(testing):

 #include <stdio.h> #include <stdlib.h> #include <string.h> int dtmsplit(char *str, const char *delim, char ***array, int *length ) { int i=0; char *token; char **res = (char **) malloc(0 * sizeof(char *)); /* get the first token */ token = strtok(str, delim); while( token != NULL ) { res = (char **) realloc(res, (i + 1) * sizeof(char *)); res[i] = token; i++; token = strtok(NULL, delim); } *array = res; *length = i; return 1; } int main() { int i; int c = 0; char **arr = NULL; int count =0; char str[80] = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC"; c = dtmsplit(str, ",", &arr, &count); printf("Found %d tokens.\n", count); for (i = 0; i < count; i++) printf("string #%d: %s\n", i, arr[i]); return(0); } 

结果:

 Found 12 tokens. string #0: JAN string #1: FEB string #2: MAR string #3: APR string #4: MAY string #5: JUN string #6: JUL string #7: AUG string #8: SEP string #9: OCT string #10: NOV string #11: DEC 

这是我的两分钱:

 int split (const char *txt, char delim, char ***tokens) { int *tklen, *t, count = 1; char **arr, *p = (char *) txt; while (*p != '\0') if (*p++ == delim) count += 1; t = tklen = calloc (count, sizeof (int)); for (p = (char *) txt; *p != '\0'; p++) *p == delim ? *t++ : (*t)++; *tokens = arr = malloc (count * sizeof (char *)); t = tklen; p = *arr++ = calloc (*(t++) + 1, sizeof (char *)); while (*txt != '\0') { if (*txt == delim) { p = *arr++ = calloc (*(t++) + 1, sizeof (char *)); txt++; } else *p++ = *txt++; } free (tklen); return count; } 

用法:

 char **tokens; int count, i; const char *str = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC"; count = split (str, ',', &tokens); for (i = 0; i < count; i++) printf ("%s\n", tokens[i]); /* freeing tokens */ for (i = 0; i < count; i++) free (tokens[i]); free (tokens); 

我认为以下解决scheme是理想的:

  • 不要销毁源string
  • 重入 – 即,您可以从一个或多个线程的任何地方安全地调用它
  • 手提
  • 正确处理多个分隔符
  • 快速高效

代码解释:

  1. 定义一个结构token来存储token的地址和长度
  2. 在最糟糕的情况下为这些分配足够的内存,这是str完全由分隔符组成的,所以strlen(str) + 1标记都是空string
  3. 扫描strlogging每个令牌的地址和长度
  4. 使用这个来分配正确大小的输出数组,包括一个NULL标记值的额外空间
  5. 使用开始和长度信息分配,复制和添加令牌 – 使用memcpystrcpy快,我们知道长度
  6. 释放令牌地址和长度数组
  7. 返回标记数组
 typedef struct { const char *start; size_t len; } token; char **split(const char *str, char sep) { char **array; unsigned int start = 0, stop, toks = 0, t; token *tokens = malloc((strlen(str) + 1) * sizeof(token)); for (stop = 0; str[stop]; stop++) { if (str[stop] == sep) { tokens[toks].start = str + start; tokens[toks].len = stop - start; toks++; start = stop + 1; } } /* Mop up the last token */ tokens[toks].start = str + start; tokens[toks].len = stop - start; toks++; array = malloc((toks + 1) * sizeof(char*)); for (t = 0; t < toks; t++) { /* Calloc makes it nul-terminated */ char *token = calloc(tokens[t].len + 1, 1); memcpy(token, tokens[t].start, tokens[t].len); array[t] = token; } /* Add a sentinel */ array[t] = NULL; free(tokens); return array; } 

注意为简洁起见,省略了malloc检查。

一般来说,我不会像这样从一个分割函数返回一个char *指针数组,因为它在调用者上负担了很多的责任来正确地释放它们。 我喜欢的一个接口是允许调用者传递一个callback函数,并为每个令牌调用它,正如我在这里所描述的: 在C中分割一个string 。

这是一个可以处理多字符分隔符的string分割函数。 请注意,如果分隔符比被分割的string长,那么bufferstringLengths将被设置为(void *) 0 ,并且numStrings将被设置为0

这个algorithm已经过testing,并且可以工作。 (免责声明:它没有被testing过非ASCIIstring,并且假定调用者给出了有效的参数)

 void splitString(const char *original, const char *delimiter, char ** & buffer, int & numStrings, int * & stringLengths){ const int lo = strlen(original); const int ld = strlen(delimiter); if(ld > lo){ buffer = (void *)0; numStrings = 0; stringLengths = (void *)0; return; } numStrings = 1; for(int i = 0;i < (lo - ld);i++){ if(strncmp(&original[i], delimiter, ld) == 0) { i += (ld - 1); numStrings++; } } stringLengths = (int *) malloc(sizeof(int) * numStrings); int currentStringLength = 0; int currentStringNumber = 0; int delimiterTokenDecrementCounter = 0; for(int i = 0;i < lo;i++){ if(delimiterTokenDecrementCounter > 0){ delimiterTokenDecrementCounter--; } else if(i < (lo - ld)){ if(strncmp(&original[i], delimiter, ld) == 0){ stringLengths[currentStringNumber] = currentStringLength; currentStringNumber++; currentStringLength = 0; delimiterTokenDecrementCounter = ld - 1; } else { currentStringLength++; } } else { currentStringLength++; } if(i == (lo - 1)){ stringLengths[currentStringNumber] = currentStringLength; } } buffer = (char **) malloc(sizeof(char *) * numStrings); for(int i = 0;i < numStrings;i++){ buffer[i] = (char *) malloc(sizeof(char) * (stringLengths[i] + 1)); } currentStringNumber = 0; currentStringLength = 0; delimiterTokenDecrementCounter = 0; for(int i = 0;i < lo;i++){ if(delimiterTokenDecrementCounter > 0){ delimiterTokenDecrementCounter--; } else if(currentStringLength >= stringLengths[currentStringNumber]){ buffer[currentStringNumber][currentStringLength] = 0; delimiterTokenDecrementCounter = ld - 1; currentStringLength = 0; currentStringNumber++; } else { buffer[currentStringNumber][currentStringLength] = (char)original[i]; currentStringLength++; } } buffer[currentStringNumber][currentStringLength] = 0; } 

示例代码:

 int main(){ const char *string = "STRING-1 DELIM string-2 DELIM sTrInG-3"; char **buffer; int numStrings; int * stringLengths; splitString(string, " DELIM ", buffer, numStrings, stringLengths); for(int i = 0;i < numStrings;i++){ printf("String: %s\n", buffer[i]); } } 

图书馆:

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

我的版本:

 int split(char* str, const char delimeter, char*** args) { int cnt = 1; char* t = str; while (*t == delimeter) t++; char* t2 = t; while (*(t2++)) if (*t2 == delimeter && *(t2 + 1) != delimeter && *(t2 + 1) != 0) cnt++; (*args) = malloc(sizeof(char*) * cnt); for(int i = 0; i < cnt; i++) { char* ts = t; while (*t != delimeter && *t != 0) t++; int len = (t - ts + 1); (*args)[i] = malloc(sizeof(char) * len); memcpy((*args)[i], ts, sizeof(char) * (len - 1)); (*args)[i][len - 1] = 0; while (*t == delimeter) t++; } return cnt; } 

爆炸&内爆 – 初始string保持不变,dynamic内存分配

 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> typedef struct { uintptr_t ptr; int size; } token_t; int explode(char *str, int slen, const char *delimiter, token_t **tokens) { int i = 0, c1 = 0, c2 = 0; for(i = 0; i <= slen; i++) { if(str[i] == *delimiter) { c1++; } } if(c1 == 0) { return -1; } *tokens = (token_t*)calloc((c1 + 1), sizeof(token_t)); ((*tokens)[c2]).ptr = (uintptr_t)str; i = 0; while(i <= slen) { if((str[i] == *delimiter) || (i == slen)) { ((*tokens)[c2]).size = (int)((uintptr_t)&(str[i]) - (uintptr_t)(((*tokens)[c2]).ptr)); if(i < slen) { c2++; ((*tokens)[c2]).ptr = (uintptr_t)&(str[i + 1]); } } i++; } return (c1 + 1); } char* implode(token_t *tokens, int size, const char *delimiter) { int i, len = 0; char *str; for(i = 0; i < len; i++) { len += tokens[i].size + 1; } str = (char*)calloc(len, sizeof(char)); len = 0; for(i = 0; i < size; i++) { memcpy((void*)&str[len], (void*)tokens[i].ptr, tokens[i].size); len += tokens[i].size; str[(len++)] = *delimiter; } str[len - 1] = '\0'; return str; } 

用法:

 int main(int argc, char **argv) { int i, c; char *exp = "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC"; token_t *tokens; char *imp; printf("%s\n", exp); if((c = explode(exp, strlen(exp), ",", &tokens)) > 0) { imp = implode(tokens, c, ","); printf("%s\n", imp); for(i = 0; i < c; i++) { printf("%.*s, %d\n", tokens[i].size, (char*)tokens[i].ptr, tokens[i].size); } } free((void*)tokens); free((void*)imp); return 0; } 

如果你愿意使用外部库,我不能推荐bstrlib 。 它需要一些额外的设置,但从长远来看更容易使用。

例如,分割下面的string,首先用bfromcstr()调用创build一个bstring 。 (一个bstring是一个字符缓冲区的包装)。 接下来,用逗号分隔string,将结果保存在一个struct bstrList ,该字段包含字段qty和数组entry ,该数组entry是一个bstring数组。

bstrlib还有很多其他的function可以在bstringbstring

易如反掌…

 #include "bstrlib.h" #include <stdio.h> int main() { int i; char *tmp = "Hello,World,sak"; bstring bstr = bfromcstr(tmp); struct bstrList *blist = bsplit(bstr, ','); printf("num %d\n", blist->qty); for(i=0;i<blist->qty;i++) { printf("%d: %s\n", i, bstr2cstr(blist->entry[i], '_')); } } 

这里列出的strtok()有一些问题 : http : //benpfaff.org/writings/clc/strtok.html

因此,最好避免strtok

现在,考虑一个包含空字段的string,如下所示:

 char myCSVString[101] = "-1.4,2.6,,-0.24,1.26"; // specify input here 

你可以使用简单的函数来将CSV格式的string转换为浮点数组来读取它们

 int strCSV2Float(float *strFloatArray , char *myCSVStringing , char delim); 

我们在这里用逗号指定分隔符。 它与其他单个字符分隔符一起工作。

请find下面的用法

 #include <stdio.h> #include <stdlib.h> int strCSV2Float(float *strFloatArray , char *myCSVStringing , char delim); void main() { char myCSVString[101] = "-1.4,2.6,,-0.24,1.26"; // specify input here float floatArr[10]; // specify size of float array here int totalValues = 0; char myDelim = ','; // specify delimiter here printf("myCSVString == %s \n",&myCSVString[0]); totalValues = strCSV2Float(&floatArr[0] , &myCSVString[0], myDelim); // call the function here int floatValueCount = 0; for (floatValueCount = 0 ; floatValueCount < totalValues ; floatValueCount++) { printf("floatArr[%d] = %f\n",floatValueCount , floatArr[floatValueCount]); } } int strCSV2Float(float *strFloatArray , char *myCSVStringing , char delim) { int strLen = 0; int commaCount =0; // count the number of commas int commaCountOld =0; // count the number of commas int wordEndChar = 0; int wordStartChar = -1; int wordLength =0; for(strLen=0; myCSVStringing[strLen] != '\0'; strLen++) // first get the string length { if ( (myCSVStringing[strLen] == delim) || ( myCSVStringing[strLen+1] == '\0' )) { commaCount++; wordEndChar = strLen; } if ( (commaCount - commaCountOld) > 0 ) { int aIter =0; wordLength = (wordEndChar - wordStartChar); char word[55] = ""; for (aIter = 0; aIter < wordLength; aIter++) { word[aIter] = myCSVStringing[strLen-wordLength+aIter+1]; } if (word[aIter-1] == delim) word[aIter-1] = '\0'; // printf("\n"); word[wordLength] = '\0'; strFloatArray[commaCount-1] = atof(&word[0]); wordLength = 0; wordStartChar = wordEndChar; commaCountOld = commaCount; } } return commaCount; } 

输出如下:

 myCSVString == -1.4,2.6,,-0.24,1.26 floatArr[0] = -1.400000 floatArr[1] = 2.600000 floatArr[2] = 0.000000 floatArr[3] = -0.240000 floatArr[4] = 1.260000 

这可能会解决你的目的

 #include <stdio.h> #include <string.h> int main() { int i = 0,j = 0,k = 0; char name[] = "jrSmith-Rock"; int length = strlen(name); char store[100][100]; for(i = 0, j = 0,k = 0; i < length;) { if((name[i] >= 'a' && name[i] <= 'z') || (name[i] >= 'A' && name[i] <= 'Z')) { store[j][k] = name[i]; k++; i++; } else{ while(! isalpha(name[i])) { i++; } j++; k = 0; } } for(i = 0; i <= j; i++) { printf("%s\n", store[i]); } return 0; } 

输出:

 jrSmith Rock 

为:哈桑A. El-Seoudy

你的机票已经closures了,所以我不能回应^^'。 但是你可以试试这个:

 ' #include <stdlib.h> #include <stdio.h> #include <string.h> int countChar(char *str) { int count; int i; i = 0; count = 0; while (str[i] != '=') // our delimiter character { i++; count++; } return (count); } void split(char *str) { int i; int j; int count; int restCount; char *str1; char *str2; i = 0; j = 0; count = countChar(str) - 1; // we have our str1 lenght, -1 for the ' ' restCount = (strlen(str) - count) -1; // we have our str2 legnht, -1 for the ' ' str1 = malloc(sizeof(char) * count); str2 = malloc(sizeof(char) * restCount); while(i < count) { str1[i] = str[i++]; } i = i + 2; // to jump directly to the first char of our str2 (no ' = ') while (str[i]) { str2[j++] = str[i++]; } printf("str1 = %s, str2 = %s\n", str1, str2); } int main() { char *str = "Xo = 100k"; split(str); return (0); }' 

Yet another answer (this was moved here from here ):

Try to use the strtok function:

see details on this topic here or here

The issue here is that you have to process the words immediately. If you want to store it in an array you have to allocate the correct size for it witch is unknown.

举个例子:

 char **Split(char *in_text, char *in_sep) { char **ret = NULL; int count = 0; char *tmp = strdup(in_text); char *pos = tmp; // This is the pass ONE: we count while ((pos = strtok(pos, in_sep)) != NULL) { count++; pos = NULL; } // NOTE: the function strtok changes the content of the string! So we free and duplicate it again! free(tmp); pos = tmp = strdup(in_text); // We create a NULL terminated array hence the +1 ret = calloc(count+1, sizeof(char*)); // TODO: You have to test the `ret` for NULL here // This is the pass TWO: we store count = 0; while ((pos = strtok(pos, in_sep)) != NULL) { ret[count] = strdup(pos); count++; pos = NULL; } free(tmp); return count; } // Use this to free void Free_Array(char** in_array) { char *pos = in_array; while (pos[0] != NULL) { free(pos[0]); pos++; } free(in_array); } 

Note : We use the same loop and function to calculate the counts (pass one) and for making the copies (pass two), in order to avoid allocation problems.

Note 2 : You may use some other implementation of the strtok the reasons mention in separate posts.

You can use this like:

 int main(void) { char **array = Split("Hello World!", " "); // Now you have the array // ... // Then free the memory Free_Array(array); array = NULL; return 0; } 

(I did not test it, so please let me know if it does not work!)