2010-07-30 4 views
3

Mon application produit des chaînes comme celle ci-dessous. J'ai besoin d'analyser les valeurs entre le séparateur en valeurs individuelles.Analyser des jetons vides à partir d'une chaîne avec strtok

2342|2sd45|dswer|2342||5523|||3654|Pswt 

J'utilise strtok de le faire dans une boucle. Pour le cinquième jeton, je reçois 5523. Cependant, je dois également tenir compte de la valeur vide entre les deux séparateurs ||. 5523 devrait être le sixième jeton, selon mes exigences.

token = (char *)strtok(strAccInfo, "|"); 

for (iLoop=1;iLoop<=106;iLoop++) { 
      token = (char *)strtok(NULL, "|"); 
} 

Une suggestion?

+2

strtok() est sans doute la pire chose dans la norme C. Vous pourriez écrire votre propre analyseur. –

Répondre

5

Dans ce cas, je préfère souvent une boucle p2 = strchr(p1, '|') avec un memcpy(s, p1, p2-p1) intérieur. C'est rapide, ne détruit pas le tampon d'entrée (donc il peut être utilisé avec const char *) et est vraiment portable (même sur embarqué).

Il est également réentrant; strtok ne l'est pas. (BTW: réentrant n'a rien à voir avec le multi-threading strtok casse déjà avec des boucles imbriquées.Un peut utiliser strtok_r mais ce n'est pas aussi portable.)

+0

J'ai utilisé votre entrée et mis à jour mon code Merci, j'ai le code que j'utilise ci-dessous comme réponse, si vous êtes intéressé – Bash

2

Sur un premier appel, la fonction prend une chaîne C comme argument pour str, dont premier caractère est utilisé comme position de départ pour rechercher des jetons. Dans les appels suivants, la fonction attend un pointeur NULL et utilise la position juste après la fin du dernier jeton comme nouvel emplacement de départ pour le balayage .

pour déterminer le début et la fin d'un jeton, la fonction première analyse à partir de la position de départ pour le premier caractère pas contenu dans délimiteurs (qui devient le début du jeton). Et puis analyse à partir de ce début de le jeton du premier caractère contenu dans les délimiteurs, qui devient la fin du jeton.

Qu'est-ce que cela signifie, c'est qu'il va sauter tout '|' caractères au début d'un jeton. Faire 5523 le 5ème jeton, que vous connaissiez déjà. Je pensais juste que j'expliquerais pourquoi (je devais le chercher moi-même). Cela dit aussi que vous n'obtiendrez pas de jetons vides.

Puisque vos données sont configurées de cette façon, vous avez plusieurs solutions possibles:
1) trouver toutes les occurrences de || et remplacez par | | (mettez un espace dedans)
2) faites un strstr 5 fois et trouvez le début du 5ème élément.

+0

Merci pour l'information. J'espère que je m'en souviendrai la prochaine fois que j'en aurai besoin. :-D Votre première solution corrige un peu mes résultats, car il existe des composants valides dans la chaîne qui renvoient un espace entre les tuyaux. La seconde solution peut devenir fastidieuse et probablement non implémentable car la chaîne peut être différente pour différents ensembles de données. – Bash

+0

@Bash - Désolé je ne pouvais pas être de plus d'aide :( –

+0

oh, vous étiez beaucoup d'aide ... l'information est le pouvoir dans notre domaine, non? – Bash

0

regarder dans strsep à la place: strsep reference

+0

strsep n'est pas portable - ne fonctionnera pas sur windows –

1

C'est une limitation de strtok. Les concepteurs avaient en tête des jetons séparés par des espaces. strtok ne fait pas grand-chose de toute façon; juste rouler votre propre analyseur. Le C FAQ has an example.

+0

J'ai Merci! – Bash

0

Utiliser autre chose que strtok. Ce n'est tout simplement pas destiné à faire ce que vous demandez. Quand j'en avais besoin, j'utilisais habituellement strcspn ou strpbrk et manipulais le reste des tokeninzing moi-même. Si cela ne vous dérange pas de modifier la chaîne d'entrée comme strtok, cela devrait être assez simple. Au moins tout de suite, quelque chose comme cela semble que cela devrait fonctionner:

// Warning: untested code. Should really use something with a less-ugly interface. 
char *tokenize(char *input, char const *delim) { 
    static char *current; // just as ugly as strtok! 
    char *pos, *ret; 
    if (input != NULL) 
     current = input; 

    if (current == NULL) 
     return current; 

    ret = current; 
    pos = strpbrk(current, delim); 
    if (pos == NULL) 
     current = NULL; 
    else { 
     *pos = '\0'; 
     current = pos+1; 
    } 
    return ret; 
} 
+0

Comme l'OP ne cherche qu'un seul caractère délimiteur, 'strchr()' pourrait être utilisé à la place de 'strpbrk()'. – caf

+0

Je l'ai fait un peu différent, merci quand même. – Bash

0

Voici la solution qui fonctionne pour moi maintenant. Merci à vous tous qui avez répondu.

J'utilise LoadRunner. Par conséquent, certaines commandes peu familières, mais je crois que le flux peut être compris assez facilement.

char strAccInfo[1024], *p2; 
int iLoop; 

Action() { //This value would come from the wrsp call in the actual script. 
    lr_save_string("323|90||95|95|null|80|50|105|100|45","test_Param"); 

    //Store the parameter into a string - saves memory. 
    strcpy(strAccInfo,lr_eval_string("{test_Param}")); 
    //Get the first instance of the separator "|" in the string 
    p2 = (char *) strchr(strAccInfo,'|'); 

    //Start a loop - Set the max loop value to more than max expected. 
    for (iLoop = 1;iLoop<200;iLoop++) { 

     //Save parameter names in sequence. 
     lr_param_sprintf("Param_Name","Parameter_%d",iLoop); 

     //Get the first instance of the separator "|" in the string (within the loop). 
     p2 = (char *) strchr(strAccInfo,'|');   

     //Save the value for the parameters in sequence. 
     lr_save_var(strAccInfo,p2 - strAccInfo,0,lr_eval_string("{Param_Name}")); 

     //Save string after the first instance of p2, as strAccInfo - for looping. 
     strcpy(strAccInfo,p2+1); 

     //Start conditional loop for checking for last value in the string. 
     if (strchr(strAccInfo,'|')==NULL) { 
      lr_param_sprintf("Param_Name","Parameter_%d",iLoop+1); 
      lr_save_string(strAccInfo,lr_eval_string("{Param_Name}")); 
      iLoop = 200;  
     } 
    } 
} 
+0

À un certain point, vous devez expliquer pourquoi vous avez des variables globales au lieu de variables locales, et pourquoi vous n'avez pas de type de retour sur la fonction (c'est très ancien style C) Ou, mieux, corrigez simplement le code afin qu'il compile proprement sous les avertissements rigoureux du compilateur. op = 200; 'réaliser 'break' est fragile. Il n'est pas clair pourquoi 200 est utilisé dans le contrôle de la boucle de toute façon. –

2
char *mystrtok(char **m,char *s,char c) 
{ 
    char *p=s?s:*m; 
    if(!*p) 
    return 0; 
    *m=strchr(p,c); 
    if(*m) 
    *(*m)++=0; 
    else 
    *m=p+strlen(p); 
    return p; 
} 
  • rentrante
  • threadsafe
  • strictement conforme ANSI
  • a besoin d'une aide-pointeur utilisé d'appeler contexte

par exemple

char *p,*t,s[]="2342|2sd45|dswer|2342||5523|||3654|Pswt"; 
for(t=mystrtok(&p,s,'|');t;t=mystrtok(&p,0,'|')) 
    puts(t); 

par exemple.

char *p,*t,s[]="2,3,4,2|2s,d4,5|dswer|23,42||5523|||3654|Pswt"; 
for(t=mystrtok(&p,s,'|');t;t=mystrtok(&p,0,'|')) 
{ 
    char *p1,*t1; 
    for(t1=mystrtok(&p1,t,',');t1;t1=mystrtok(&p1,0,',')) 
    puts(t1); 
} 

votre travail :) outil char * c en tant que paramètre 3

Questions connexes