2010-12-28 14 views
7

Estoy usando strtok() en c para analizar una cadena csv. Primero lo tokino para descubrir cuántos tokens hay, así puedo asignar una cadena del tamaño correcto. Luego sigo usando la misma variable que utilicé la última vez para la tokenización. Cada vez que lo hago por segunda vez, strtok(NULL, ",") devuelve NULL aunque todavía hay más tokens para analizar. ¿Alguien puede decirme qué estoy haciendo mal?tokenizar una cadena dos veces en 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, ","); 
} 

Así que en ese segundo bucle while siempre termina después de la primera ficha se encuentra a pesar de que hay más fichas. ¿Alguien sabe lo que estoy haciendo mal?

+2

¿Cómo es que todo el mundo sabe qué 'strtok()' es en estos días, pero nadie ha leído la documentación? Nadie me lo contó cuando estaba aprendiendo C, pero tan pronto como tuve que saberlo, lo leí. –

Respuesta

16

strtok() modifica la cadena en la que opera, reemplazando los caracteres del delimitador con valores nulos. Entonces, si desea usarlo más de una vez, tendrá que hacer una copia.

+4

+1: Y es por eso que usar 'strtok()' a menudo no es tan buena idea después de todo ... –

+0

Usted gana. +1 para la respuesta rápida. – Septagram

2

No hay necesariamente una necesidad de hacer una copia: strtok() modifica la cadena que está tokenizando, pero en la mayoría de los casos eso simplemente significa que la cadena ya está tokenizada si desea tratar con los tokens nuevamente.

Aquí es su programa modificado un poco para procesar las señales después de la primera pasada:

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

Tenga en cuenta que esto es por desgracia más complicado de lo que por primera vez - la llamada a strspn() necesita ser realizada después de saltarse el '\ 0 'colocado por strtok() desde strtok() omitirá cualquier carácter delimitador principal para el token que devuelve (sin reemplazar el carácter delimitador en la fuente).

+0

Otra forma sería almacenar los punteros del token desde la primera pasada en una matriz. Por supuesto, eso significaría tener un número máximo de tokens o una matriz dinámica. Pero eso podría funcionar también. –

1

Utilice strsep - en realidad actualiza su puntero. En tu caso, deberías seguir llamando a NULL o pasar la dirección de tu cadena. El único problema con strsep es si se asignó previamente en el montón, mantenga un puntero al principio y luego libérelo más tarde.

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

char * cadena; token de char *; token = strsep (& cadena, ",");

strtok se utiliza en su introducción normal al curso C - use strsep, es mucho mejor. :-) No te confundas con "oh mierda - tengo que pasar NULL todavía porque primo jodió mi posición".