2010-12-28 14 views
7

Sto usando strtok() in c per analizzare una stringa csv. Per prima cosa ne faccio un token per scoprire quanti token ci sono in modo da poter allocare una stringa della dimensione corretta. Quindi utilizzo la stessa variabile che ho usato l'ultima volta per la tokenizzazione. Ogni volta che lo faccio una seconda volta sebbene lo strtok(NULL, ",") restituisca NULL anche se ci sono ancora più token da analizzare. Qualcuno può dirmi cosa sto facendo di sbagliato?tokenizing una stringa due volte in c con strtok()

char* tok; 
int count = 0; 
tok = strtok(buffer, ","); 
while(tok != NULL) { 
    count++; 
    tok = strtok(NULL, ","); 
} 

//allocate array 

tok = strtok(buffer, ","); 
while(tok != NULL) { 
    //do other stuff 
    tok = strtok(NULL, ","); 
} 

così via, che secondo ciclo while finisce sempre dopo il primo token si trova anche se ci sono più gettoni. Qualcuno sa cosa sto sbagliando?

+2

Come è che a quanto pare tutti sanno cosa 'strtok()' è in questi giorni, ma nessuno ha letto la documentazione? Nessuno me ne ha parlato quando stavo imparando C, ma appena ho dovuto saperlo, ho letto su di esso. –

risposta

16

strtok() modifica la stringa su cui opera, sostituendo i caratteri delimitatore con valori null. Quindi se vuoi usarlo più di una volta, dovrai fare una copia.

+4

+1: Ed è per questo che usare 'strtok()' spesso non è una buona idea dopotutto ... –

+0

Hai vinto. +1 per la risposta veloce. – Septagram

2

Non c'è necessariamente bisogno di fare una copia - strtok() modifica la stringa che sta per tokenizzare, ma nella maggior parte dei casi significa semplicemente che la stringa è già tokenizzata se si desidera gestire nuovamente i token.

Ecco il programma modificato un po 'per elaborare i gettoni dopo il primo passaggio:

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

int main() 
{ 
    int i; 
    char buffer[] = "some, string with , tokens"; 

    char* tok; 
    int count = 0; 
    tok = strtok(buffer, ","); 
    while(tok != NULL) { 
     count++; 
     tok = strtok(NULL, ","); 
    } 


    // walk through the tokenized buffer again 
    tok = buffer; 

    for (i = 0; i < count; ++i) { 
     printf("token %d: \"%s\"\n", i+1, tok); 
     tok += strlen(tok) + 1; // get the next token by skipping past the '\0' 
     tok += strspn(tok, ","); // then skipping any starting delimiters 
    } 

    return 0; 
    } 

notare che questa è, purtroppo, più difficile che ho postato - la chiamata a strspn() deve essere eseguita dopo aver saltato il '\ 0 'inserito da strtok() dal strtok() salterà tutti i principali caratteri di delimitazione per il token che restituisce (senza sostituire il carattere delimitatore nell'origine).

+0

Un altro modo sarebbe quello di memorizzare i puntatori di token dal primo passaggio in un array. Ovviamente, ciò significherebbe avere un numero massimo di token o un array dinamico. Ma potrebbe funzionare anche questo. –

1

Usa strsep: aggiorna effettivamente il puntatore. Nel tuo caso dovresti continuare a chiamare NULL anziché passare l'indirizzo della tua stringa. L'unico problema con strsep è se è stato precedentemente assegnato all'heap, mantenere un puntatore all'inizio e poi liberarlo in seguito.

char * strsep (char ** stringa, char * delim);

char * stringa; codice * token; token = strsep (& stringa, ",");

strtok è utilizzato nel normale corso di introduzione in C - usa strsep, è molto meglio. :-) Non ci si può confondere su "oh merda - devo passare in NULL ancora perché strzo ha rovinato il mio posizionamento".