2008-11-05 16 views
23

He intentado tokenizar una cadena usando SPACE como delimitador pero no funciona. ¿Alguien tiene alguna sugerencia sobre por qué no funciona?Tokenizing strings en C

Editar: tokenizar usando:

strtok(string, " "); 

El código es el siguiente

pch = strtok (str," "); 
while (pch != NULL) 
{ 
    printf ("%s\n",pch); 
    pch = strtok (NULL, " "); 
} 
+0

su ejemplo recibirá el primer token, consulte gbjbaanb's o mis respuestas para un uso adecuado. –

+0

OK. Ahora estamos llegando a algún lado. ¿Qué comportamiento esperas que no obtengas? – dmckee

+0

Su código es correcto, por favor, háganos saber cuál es su cadena de entrada y el resultado. –

Respuesta

0

Al leer la documentación strtok, veo que necesita para pasar de un puntero NULL después de la primera "inicializar " llamada. Quizás no hiciste eso. Solo una conjetura, por supuesto.

38

hacerlo de esta manera:

char s[256]; 
strcpy(s, "one two three"); 
char* token = strtok(s, " "); 
while (token) { 
    printf("token: %s\n", token); 
    token = strtok(NULL, " "); 
} 

Nota: strtok modifica la cadena de su tokenising, por lo que no puede haber una const char*.

+0

heh, publicamos casi lo mismo a la misma hora exacta :-P –

+0

Veo, odio eso. Afortunadamente, presiono Post segundos antes que tú, así que nayanayayayaya :-) Ten una votación. – gbjbaanb

+6

Voy a devolver el favor;) –

32

He aquí un ejemplo de strtok uso, tenga en cuenta que strtok es destructiva de su cadena de entrada (y por lo tanto no puede vez usarse en una cadena constante

char *p = strtok(str, " "); 
while(p != NULL) { 
    printf("%s\n", p); 
    p = strtok(NULL, " "); 
} 

Básicamente lo que hay que tener en cuenta es que la aprobación de una NULL como primer parámetro a strtok dice que para obtener el siguiente token de la cadena a la que se tokenizing anteriormente.

+1

¿Cómo sabe 'strtok()' cuándo obtener el siguiente token de la cadena que estaba formando tokens previamente? Para mí, parece que 'strtok()' debe tokenizar el valor 'NULL'. Esperaría un error. – polemon

+3

'strtok' tiene una variable de estado interna que rastrea la cadena que se está tokenizando. Cuando le pase 'NULL',' strtok' continuará usando esta variable de estado. Cuando pasa un valor no nulo, la variable de estado se restablece. En otras palabras: pasar 'NULL' significa" continuar tokenizando la misma cadena ". –

+2

Gracias por aclarar. Pero de todos modos parece un diseño horrible. – polemon

3

se puede simplificar el código mediante la introducción de una variable adicional.

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

int main() 
{ 
    char str[100], *s = str, *t = NULL; 

    strcpy(str, "a space delimited string"); 
    while ((t = strtok(s, " ")) != NULL) { 
     s = NULL; 
     printf(":%s:\n", t); 
    } 
    return 0; 
} 
6

strtok puede ser muy peligroso. No es seguro para subprocesos. Su uso previsto debe ser repetido una y otra vez en un bucle, pasando el resultado de la llamada anterior. La función strtok tiene una variable interna que almacena el estado de la llamada strtok. Este estado no es exclusivo de cada hilo: es global. Si cualquier otro código usa strtok en otro hilo, obtienes problemas. ¡No es el tipo de problemas que quieres rastrear tampoco!

Recomendaría buscar una implementación de expresiones regulares, o usar sscanf para separar la cadena.

Prueba esto:

char strprint[256]; 
char text[256]; 
strcpy(text, "My string to test"); 
while (sscanf(text, "%s %s", strprint, text) > 0) { 
    printf("token: %s\n", strprint); 
} 

Nota: La cadena de 'texto' es destruido, ya que está separado. Puede que este no sea el comportamiento preferido =)

+3

De hecho, si nos fijamos en las implementaciones de strtok modernas, tienden a utilizar el almacenamiento local de subprocesos (MSVC ciertamente lo ha hecho durante años y años), por lo que son seguros para subprocesos. Todavía es una función arcaica que evitaría, aunque ... –

+3

strtok_r es una versión segura para subprocesos de strtok http://pubs.opengroup.org/onlinepubs/009695399/functions/strtok.html –

2

He hecho algunas funciones de cadena para dividir valores, usando menos punteros ya que este código está destinado a ejecutarse en procesadores PIC18F.Esos procesadores no maneja muy bien con los punteros cuando tiene pocos RAM libre disponible:

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

char POSTREQ[255] = "pwd=123456&apply=Apply&d1=88&d2=100&pwr=1&mpx=Internal&stmo=Stereo&proc=Processor&cmp=Compressor&ip1=192&ip2=168&ip3=10&ip4=131&gw1=192&gw2=168&gw3=10&gw4=192&pt=80&lic=&A=A"; 

int findchar(char *string, int Start, char C) { 
    while((string[Start] != 0)) { Start++; if(string[Start] == C) return Start; } 
    return -1; 
} 

int findcharn(char *string, int Times, char C) { 
    int i = 0, pos = 0, fnd = 0; 

    while(i < Times) { 
     fnd = findchar(string, pos, C); 
     if(fnd < 0) return -1; 
     if(fnd > 0) pos = fnd; 
     i++; 
    } 
    return fnd; 
} 

void mid(char *in, char *out, int start, int end) { 
    int i = 0; 
    int size = end - start; 

    for(i = 0; i < size; i++){ 
     out[i] = in[start + i + 1]; 
    } 
    out[size] = 0; 
} 

void getvalue(char *out, int index) { 
    mid(POSTREQ, out, findcharn(POSTREQ, index, '='), (findcharn(POSTREQ, index, '&') - 1)); 
} 

void main() { 
    char n_pwd[7]; 
    char n_d1[7]; 

    getvalue(n_d1, 1); 

    printf("Value: %s\n", n_d1); 
} 
-1
int not_in_delimiter(char c, char *delim){ 

    while(*delim != '\0'){ 
      if(c == *delim) return 0; 
      delim++; 
    } 
    return 1; 
} 

char *token_separater(char *source, char *delimiter, char **last){ 

char *begin, *next_token; 
char *sbegin; 

/*Get the start of the token */ 
if(source) 
    begin = source; 
else 
    begin = *last; 

sbegin = begin; 

/*Scan through the string till we find character in delimiter. */ 
while(*begin != '\0' && not_in_delimiter(*begin, delimiter)){ 
     begin++; 
} 

/* Check if we have reached at of the string */ 
if(*begin == '\0') { 
/* We dont need to come further, hence return NULL*/ 
    *last = NULL; 
    return sbegin; 
} 
/* Scan the string till we find a character which is not in delimiter */ 
next_token = begin; 
while(next_token != '\0' && !not_in_delimiter(*next_token, delimiter)) { 
    next_token++; 
} 
/* If we have not reached at the end of the string */ 
if(*next_token != '\0'){ 
    *last = next_token--; 
    *next_token = '\0'; 
    return sbegin; 
} 
} 

void main(){ 

    char string[10] = "abcb_dccc"; 
    char delim[10] = "_"; 
    char *token = NULL; 
    char *last = "" ; 
    token = token_separater(string, delim, &last); 
    printf("%s\n", token); 
    while(last){ 
      token = token_separater(NULL, delim, &last); 
      printf("%s\n", token); 
    } 

}

Usted puede leer el análisis de los detalles en el blog mencionado en mi perfil :)

+0

Agradable, @jitsceait, pero ¿Qué sucede si tengo dos delimitadores juntos en la entrada? Voy a cambiar un poco tu código. –

+0

Creo que he agregado un caso de prueba para delimitadores consecutivos y estaba funcionando. ¿Podrías por favor resaltar el código que has cambiado? – jitsceait

0

Aquí es otra implementación strtok(), que tiene la capacidad de reconocer delimitadores consecutivos (la biblioteca estándar strtok() no tiene esto)

La función es una parte de la biblioteca de cadenas con licencia de BSD, llamada zString. Que son más que bienvenidos a contribuir :)

https://github.com/fnoyanisi/zString

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

Como se ha mencionado en anteriores, ya que strtok(), o la que implmented anteriormente, se basa en una variable static *char para preservar la ubicación de la última delimitador entre llamadas consecutivas, se debe tener especial cuidado al tratar con aplicaciones de subprocesos múltiples.