Separar cadena con delimitadores en C

¿Cómo escribo una función para dividir y devolver una matriz para una cadena con delimitadores en el lenguaje de progtwigción C?

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

Puede usar la strtok() para dividir una cadena (y especificar el delimitador que se usará). Tenga en cuenta que strtok() modificará la cadena pasada a él. Si se requiere la cadena original en otro lugar, haga una copia y pase la copia a strtok() .

EDITAR:

Ejemplo (tenga en cuenta que no maneja delimitadores consecutivos, “JAN ,,, FEB, MAR”, por ejemplo):

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

Salida:

 $ ./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] 

Creo que strsep sigue siendo la mejor herramienta para esto:

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

Esa es literalmente una línea que divide una cuerda.

Los paréntesis adicionales son un elemento estilístico para indicar que estamos probando intencionalmente el resultado de una tarea, no un operador de igualdad == .

Para que funcione ese patrón, token y str ambos tienen tipo char * . Si comenzaste con un literal de cadena, entonces querrías hacer una copia primero:

 // 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); 

Si dos delimitadores aparecen juntos en str , obtendrá un valor de token que es la cadena vacía. El valor de str se modifica en que cada delimitador encontrado se sobrescribe con un byte cero, otra buena razón para copiar la cadena que se analiza primero.

En un comentario, alguien sugirió que strtok es mejor que strsep porque strsep es más portátil. Ubuntu y Mac OS X tienen strsep ; es seguro adivinar que otros sistemas unixy también lo hacen. Windows carece de strsep , pero tiene strbrk que permite este reemplazo corto y dulce de strsep :

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

Aquí hay una buena explicación de strsep vs strsep . Los pros y los contras pueden ser juzgados subjetivamente; sin embargo, creo que es una señal reveladora de que strsep fue diseñado como un reemplazo para strtok .

Tokenizador de cadenas este código debería ponerlo en la dirección correcta.

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

El siguiente método hará todo el trabajo (asignación de memoria, contando la longitud) para usted. Más información y descripción se puede encontrar aquí – Implementación del método Java String.split () para dividir la cadena C

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

Cómo usarlo:

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

En el ejemplo anterior, habría una manera de devolver una matriz de cadenas terminadas nulas (como desee) en la cadena. Sin embargo, no permitiría pasar una cadena literal, ya que tendría que ser modificada por la función:

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

Probablemente haya una manera más ordenada de hacerlo, pero entiendes la idea.

 #include  #include  #include  #include  /** * 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 

Intenta usar esto.

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

Debajo está mi implementación de strtok strtok() de la biblioteca zString . zstring_strtok() difiere del zstring_strtok() de la biblioteca estándar strtok() en la forma en que trata los delimitadores consecutivos.

Simplemente eche un vistazo al código a continuación, seguro de que obtendrá una idea sobre cómo funciona (traté de usar tantos comentarios como pude)

 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 

A continuación se muestra un ejemplo de uso ...

  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) 

La biblioteca se puede descargar de Github https://github.com/fnoyanisi/zString

Aquí están mis dos centavos:

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

Uso:

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

No probado, probablemente incorrecto, pero debería darle una buena ventaja sobre cómo debería funcionar:

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

Esta función toma una cadena char * y la divide por el delimitador. Puede haber múltiples delimitadores en una fila. Tenga en cuenta que la función modifica la cadena original. Primero debe hacer una copia de la secuencia original si necesita que el original permanezca inalterado. Esta función no usa ninguna llamada de función cstring, por lo que podría ser un poco más rápida que otras. Si no le importa la asignación de memoria, puede asignar sub_strings en la parte superior de la función con size strlen (src_str) / 2 y (como la “versión” de c ++ mencionada) omita la mitad inferior de la función. Si hace esto, la función se reduce a O (N), pero la forma optimizada de memoria que se muestra a continuación es O (2N).

La función:

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

Cómo usarlo:

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

Mi enfoque es escanear la cadena y dejar que los punteros apuntan a cada carácter después de los delimitadores (y el primer carácter), al mismo tiempo, asignar las apariencias del deliminador en cadena a ‘\ 0’.
Primero haga una copia de la secuencia original (ya que es constante), luego obtenga el número de divisiones por escaneo y páselo al parámetro del puntero len . Después de eso, apunte el puntero del primer resultado al puntero de la cadena de copia, luego escanee la cadena de copia: una vez que encuentre un delimitador, asígnelo a ‘\ 0’ para terminar la cadena de resultados anterior y apunte el siguiente puntero de cadena de resultados al siguiente puntero del personaje

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

Este método optimizado crea (o actualiza un conjunto existente de punteros en * resultado y devuelve la cantidad de elementos en * recuento.

Use “max” para indicar la cantidad máxima de cadenas que espera (cuando especifica una matriz existente o cualquier otra entrada), de lo contrario, ajústelo a 0

Para comparar con una lista de delimitadores, defina delim como un char * y reemplace la línea:

 if (str[i]==delim) { 

con las dos siguientes líneas:

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

Disfrutar

 #include  #include  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 

Ejemplo de uso:

 #include  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 

Mi código (probado):

 #include  #include  #include  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); } 

Resultado:

 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 

Creo que la siguiente solución es ideal:

  • No destruye la cadena fuente
  • Reentrante – es decir, puede llamarlo de manera segura desde cualquier lugar en uno o más hilos
  • Portátil
  • Maneja múltiples separadores correctamente
  • Rápido y eficiente

Explicación del código:

  1. Definir un token estructura para almacenar la dirección y la duración de los tokens
  2. Asigne suficiente memoria para estos en el peor de los casos, que es cuando str está compuesta completamente por separadores, por lo que hay strlen(str) + 1 tokens, todos ellos cadenas vacías.
  3. Escanee la grabación de la dirección y la longitud de cada token
  4. Utilice esto para asignar la matriz de salida del tamaño correcto, incluido un espacio adicional para un valor centinela NULL
  5. Asigne, copie y agregue los tokens usando la información de inicio y duración: use memcpy ya que es más rápido que strcpy y conocemos las longitudes
  6. Libere la dirección de token y la matriz de longitud
  7. Devuelve la matriz de tokens
 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; } 

Tenga en cuenta la verificación malloc omitida por brevedad.

En general, no devolvería una matriz de caracteres char * de una función dividida como esta ya que le da mucha responsabilidad a la persona que llama para liberarlos correctamente. Una interfaz que prefiero es permitir que la persona que llama pase una función de callback y llame a esto para cada token, como he descrito aquí: Dividir una cadena en C.

Esta es una función de división de cadenas que puede manejar delimitadores de múltiples caracteres. Tenga en cuenta que si el delimitador es más largo que la cadena que se está stringLengths , entonces buffer y stringLengths se establecerán en (void *) 0 , y numStrings se establecerá en 0 .

Este algoritmo ha sido probado y funciona. (Descargo de responsabilidad: no se ha probado para cadenas que no sean ASCII, y se supone que la persona que llama dio parámetros válidos)

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

Código de muestra:

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

Bibliotecas:

 #include  #include  #include  

Mi version:

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

Explotar e implosionar – la cadena inicial permanece intacta, asignación de memoria dinámica

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

Uso:

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

Si está dispuesto a usar una biblioteca externa, no puedo recomendar bstrlib suficiente. Requiere un poco de configuración adicional, pero es más fácil de usar a largo plazo.

Por ejemplo, divida la cadena a continuación, primero crea una bstring con la llamada bfromcstr() . (Una bstring es una envoltura alrededor de un búfer de caracteres). A continuación, divida la cadena en comas, guardando el resultado en struct bstrList , que tiene campos qty y una entry matriz, que es una matriz de bstring s.

bstrlib tiene muchas otras funciones para operar en bstring s

Muy fácil…

 #include "bstrlib.h" #include  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;iqty;i++) { printf("%d: %s\n", i, bstr2cstr(blist->entry[i], '_')); } } 

Hay algunos problemas con strtok () enumerados aquí: http://benpfaff.org/writings/clc/strtok.html

Por lo tanto, es mejor evitar strtok .

Ahora, considere una cadena que contenga un campo vacío de la siguiente manera:

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

Puede usar una función simple para poder convertir cadenas en formato CSV para leerlas en una matriz flotante :

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

Especificamos el delimitador aquí como una coma. Funciona con otro delimitador de caracteres individuales.

Encuentre el uso a continuación:

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

La salida es la siguiente:

 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 

Para: Hassan A. El-Seoudy

Su boleto está cerrado, así que no puedo responderlo ^^ ‘. Pero puedes intentar esto:

 ' #include  #include  #include  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.

Así por ejemplo:

 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!)

This may solve your purpose

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

Salida:

 jrSmith Rock 

This is different approach, working for large files too. https://onlinegdb.com/BJlWVdzGf