Dividi la stringa con delimitatori in C

Come scrivere una funzione per dividere e restituire un array per una stringa con delimitatori nel linguaggio di programmazione C?

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

È ansible utilizzare la funzione strtok() per dividere una stringa (e specificare il delimitatore da utilizzare). Si noti che strtok() modificherà la stringa passata in essa. Se la stringa originale è richiesta altrove, creane una copia e passa la copia a strtok() .

MODIFICARE:

Esempio (nota che non gestisce i delimitatori consecutivi, “JAN ,,, FEB, MAR” per esempio):

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

Produzione:

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

Penso che strsep sia ancora lo strumento migliore per questo:

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

Questa è letteralmente una riga che divide una stringa.

Le parentesi extra sono un elemento stilistico per indicare che stiamo testando intenzionalmente il risultato di un compito, non un operatore di uguaglianza == .

Perché quel modello funzioni, i token e gli str hanno entrambi char * . Se hai iniziato con una stringa letterale, dovresti prima farne una copia:

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

Se due delimitatori appaiono insieme in str , otterrai un valore token che è la stringa vuota. Il valore di str viene modificato in quanto ogni delimitatore rilevato viene sovrascritto con un byte zero, un’altra buona ragione per copiare prima la stringa che viene analizzata.

In un commento, qualcuno ha suggerito che strtok è meglio di strsep perché strtok è più portabile. Ubuntu e Mac OS X hanno strsep ; è ansible indovinare anche altri sistemi unixy. Windows non ha strsep , ma ha strbrk che abilita questa sostituzione breve e dolce dello 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; } 

Ecco una buona spiegazione di strsep vs strtok . I pro e i contro possono essere giudicati soggettivamente; tuttavia, penso che sia un segno significativo che strsep stato progettato come sostituto di strtok .

Stringa tokenizer questo codice dovrebbe metterti nella giusta direzione.

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

Il seguente metodo farà tutto il lavoro (allocazione della memoria, contando la lunghezza) per te. Ulteriori informazioni e descrizioni possono essere trovate qui – Implementazione del metodo Java String.split () per dividere la stringa 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; } 

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

Nell’esempio sopra, ci sarebbe un modo per restituire una serie di stringhe terminate null (come vuoi) in posizione nella stringa. Tuttavia, non sarebbe ansible passare una stringa letterale, poiché dovrebbe essere modificata dalla funzione:

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

C'è probabilmente un modo più ordinato per farlo, ma tu hai l'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 

Prova a usare questo.

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

Di seguito è la mia implementazione strtok() dalla libreria zString . zstring_strtok() differisce dallo strtok() della libreria standard nel modo in cui tratta i delimitatori consecutivi.

Dai un’occhiata al codice qui sotto, certo che avrai un’idea di come funziona (ho cercato di usare quanti più commenti ansible)

 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 

Di seguito è riportato un esempio di utilizzo ...

  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 libreria può essere scaricata da Github https://github.com/fnoyanisi/zString

Ecco i miei due centesimi:

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

Non testato, probabilmente sbagliato, ma dovrebbe darti un buon vantaggio su come dovrebbe funzionare:

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

Questa funzione prende una stringa char * e la divide dal deliminatore. Possono esserci più deliminatori in fila. Si noti che la funzione modifica la stringa originale. Devi prima fare una copia della stringa originale se hai bisogno che l’originale rimanga inalterato. Questa funzione non usa alcuna chiamata di funzione cstring, quindi potrebbe essere un po ‘più veloce di altre. Se non ti interessa l’allocazione della memoria, puoi allocare sotto_strings nella parte superiore della funzione con dimensione strlen (src_str) / 2 e (come la “versione” c ++ menzionata) salta la metà inferiore della funzione. Se si esegue questa operazione, la funzione viene ridotta a O (N), ma il modo ottimizzato per la memoria mostrato di seguito è O (2N).

La funzione:

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

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

Il mio approccio è quello di scansionare la stringa e lasciare che i puntatori puntino su ogni carattere dopo i delimitatori (e il primo carattere), allo stesso tempo assegnano le apparenze del delimitatore nella stringa a ‘\ 0’.
Prima crea una copia della stringa originale (poiché è costante), quindi ottieni il numero di divisioni eseguendo una scansione passandola al parametro pointer len . Quindi, puntare il primo puntatore del risultato sul puntatore della stringa di copia, quindi eseguire la scansione della stringa di copia: una volta incontrato un deliminatore, assegnarlo a ‘\ 0’ in modo che la stringa del risultato precedente sia terminata e puntare il successivo puntatore della stringa al successivo puntatore di caratteri.

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

Questo metodo ottimizzato crea (o aggiorna una serie esistente) di puntatori in * result e restituisce il numero di elementi in * count.

Usa “max” per indicare il numero massimo di stringhe che ti aspetti (quando specifichi un array esistente o qualsiasi altro Reaseon), altrimenti impostalo su 0

Per confrontare un elenco di delimitatori, definisci delim come char * e sostituisci la riga:

 if (str[i]==delim) { 

con le due linee seguenti:

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

Godere

 #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 

Esempio di utilizzo:

 #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 

Il mio codice (testato):

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

Risultato:

 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 

Penso che la seguente soluzione sia ideale:

  • Non distrugge la stringa di origine
  • Re-entrant – cioè, puoi tranquillamente chiamarlo da qualsiasi posizione in uno o più thread
  • Portatile
  • Gestisce correttamente più separatori
  • Veloce ed efficiente

Spiegazione del codice:

  1. Definire un token struttura per memorizzare l’indirizzo e le lunghezze dei token
  2. Assegna abbastanza memoria per questi nel peggiore dei casi, che è quando str è composto interamente da separatori quindi ci sono strlen(str) + 1 token, tutti loro stringhe vuote
  3. Scansiona str registrando l’indirizzo e la lunghezza di ogni token
  4. Da utilizzare per allocare l’array di output della dimensione corretta, incluso uno spazio aggiuntivo per un valore sentinella NULL
  5. Assegna, copia e aggiungi i token utilizzando le informazioni di avvio e lunghezza – usa memcpy poiché è più veloce di strcpy e conosciamo le lunghezze
  6. Liberare l’indirizzo del token e l’array di lunghezza
  7. Restituisce la serie di token
 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; } 

Nota il controllo di malloc omesso per brevità.

In generale, non restituirei una matrice di puntatori char * da una funzione di divisione come questa in quanto pone molta responsabilità sul chiamante per liberarli correttamente. Un'interfaccia che preferisco è quella di permettere al chiamante di passare una funzione di callback e chiamarla per ogni token, come ho descritto qui: Split a String in C.

Questa è una funzione di divisione delle stringhe in grado di gestire i delimitatori a più caratteri. Notare che se il delimitatore è più lungo della stringa che viene suddivisa, il buffer e stringLengths verranno impostati su (void *) 0 e numStrings sarà impostato su 0 .

Questo algoritmo è stato testato e funziona. (Dichiarazione di non responsabilità: non è stato testato per stringhe non ASCII e presuppone che il chiamante abbia fornito parametri validi)

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

Codice d’esempio:

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

biblioteche:

 #include  #include  #include  

La mia versione:

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

Esplodi e implodi: la stringa iniziale rimane intatta, l’allocazione dynamic della memoria

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

Se sei disposto ad usare una libreria esterna, non posso raccomandare abbastanza bstrlib . Ci vuole un po ‘di setup extra, ma è più facile da usare a lungo termine.

Ad esempio, bstring la stringa sottostante, una prima crea un bstring con la chiamata bfromcstr() . (Un bstring è un wrapper attorno a un buffer di caratteri). Quindi, struct bstrList la stringa su virgole, salvando il risultato in una struct bstrList , che contiene i campi qty e una entry dell’array, che è una matrice di bstring s.

bstrlib ha molte altre funzioni per operare su bstring s

Facile come torta …

 #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], '_')); } } 

Ci sono alcuni problemi con strtok () elencato qui: http://benpfaff.org/writings/clc/strtok.html

Quindi, è meglio evitare lo strtok .

Ora, considera una stringa contenente un campo vuoto come segue:

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

È ansible utilizzare la funzione semplice per convertire String in formato CSV per leggerli in una matrice mobile :

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

Abbiamo specificato il delimitatore qui come una virgola. Funziona con altri delimitatori a singolo carattere.

Si prega di trovare l’ utilizzo di seguito:

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

L'output è il seguente:

 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 

Per: Hassan A. El-Seoudy

Il tuo biglietto è chiuso, quindi non posso rispondere ad esso ^^ ‘. But you can try this:

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

Quindi per esempio:

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

Output :

 jrSmith Rock 

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