2016-06-10 2 views
0

A titre d'exemple, entrée:I ont une chaîne str qui présente deux groupement (peut être plus) que je voudrais convertir en tableaux d'entiers en C

c[] = "[1,2,3][5,7,8]" 

sortie:

a = [1,2,3] //of type int a[] 
b = [5,7,8] //of type int b[] 

J'ai essayé d'utiliser strtok pour supprimer "]". Mais, quand j'utilise strtok la prochaine fois, je ne suis pas capable de l'utiliser. Si je tente d'imprimer la sortie, je reçois

[1,2,3 
[1 
2 
3 

au lieu de

[1,2,3 
[1 
2 
3 
[5,7,8 
[5 
7 
8 

Code qui je jusqu'à présent

char c[] = "[1,2,3][5,7,8]"; 

char *token = strtok(c, "]"); 
for (token; token != NULL ; token = strtok(NULL, "]")){ 
    puts(token); 
    char *comma = strtok(c, ","); 
    for (comma; comma != NULL; comma = strtok(NULL, ",")){ 
     puts(comma); 
    } 
} 
+0

Pouvez-vous clarifier la sortie requise? L'exemple syntaxiquement incorrect * input * est clarifié dans l'exemple de code, mais le premier exemple de sortie est commenté comme '// de type int a []'. Voulez-vous dire que la sortie est 'int a [] = {1, 2, 3};'? Et l'exemple suivant * "au lieu de" * ne correspond pas au premier exemple. –

+0

'strtok' ne fonctionnera pas car vous devez rechercher une virgule * ou *'] '. 'strtok' peut le faire, mais il ne vous dira pas lequel il a trouvé. Vous devez donc analyser la chaîne vous-même, en utilisant une boucle 'for' qui examine un caractère à la fois. – user3386109

+0

@WeatherVane Oui, je voulais dire [] = {1, 2, 3}. Désolé pour la confusion. – user3213116

Répondre

0

Votre problème est que strtok a Mémoire. La première fois que vous passez une chaîne, elle est mémorisée et utilisée à plusieurs reprises tant que vous passez en NULL en tant que premier paramètre.

Cependant, dans votre boucle, vous appelez à nouveau strtok avec un paramètre. Donc cette nouvelle chaîne (qui est le premier jeton seulement) est placée dans la mémoire de strtok, et après qu'elle soit complètement traitée dans la boucle interne, il n'y a plus rien à marquer dans la boucle externe.

Jetez un oeil à ce thread, il explique plus en détail comment strtok fonctionne. Cependant, vous avez de la chance: strtok manipule la chaîne que vous avez passée en place (c'est pourquoi vous devez passer la chaîne à symboliser char*, mais les délimiteurs peuvent être const char*). Ainsi, vous pouvez faire ceci:

char c[] = "[1,2,3][5,7,8]"; 

char* next = c; 
char* token; 
while((token = strtok(next, "]"))) 
{ 
    puts(token); 
    next += strlen(token) + 1; // move next behind the token 
    token = strtok(token, ","); 
    do 
    { 
     puts(token); 
    } 
    while((token = strtok(NULL, ","))); 
} 

Si vous vous interrogez sur les parenthèses supplémentaires, ceux-ci doivent éviter un avertissement dans le compilateur (« cession possible au lieu de comparaison »).

0

Cette solution possède deux boucles imbriquées de strtok_s, car strtok n'est pas réentrant. C'est MSVC, certains systèmes implémenter le strtok_r similaire.

J'ai créé une sortie en conformité avec le haut de votre question, cela peut être modifié pour convenir à d'autres sorties, ce n'était pas très clair. Dans ce cas, il n'était pas vraiment nécessaire d'avoir deux boucles imbriquées, mais vos exemples suivants confondent le problème en décomposant l'entrée comma'ed.

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

int main(void) { 
    char c[] = "[1,2,3][5,7,8]"; 
    char *tok1 = NULL; 
    char *tok2 = NULL; 
    char *end1 = NULL; 
    char *end2 = NULL; 
    int comma = 0; 
    char identifier = 'a'; 

    tok1 = strtok_s(c, "[]", &end1); 
    while(tok1 != NULL) {      // outer loop splitting [bracket] parts 
     printf("%c = [", identifier); 
     comma = 0;        // control comma output 
     tok2 = strtok_s(tok1, ",", &end2); 
     while(tok2 != NULL) {     // inner loop splitting ,comma, parts 
      if(comma) {       // check if comma required 
       printf(","); 
      } 
      printf("%s", tok2); 
      comma = 1;       // a comma will be needed 
      tok2 = strtok_s(NULL, ",", &end2); 
     } 
     printf("] //of type int %c[]\n", identifier); 
     identifier++; 
     tok1 = strtok_s(NULL, "[]", &end1); 
    } 
    return 0; 
} 

Le programme plus simple où vous n'avez pas besoin d'examiner dans les [crochets] est

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

int main(void) { 
    char c[] = "[1,2,3][5,7,8]"; 
    char *tok = NULL; 
    char identifier = 'a'; 

    tok = strtok(c, "[]"); 
    while(tok != NULL) { 
     printf("%c = [%s] //of type int %c[]\n", identifier, tok, identifier); 
     identifier++; 
     tok = strtok(NULL, "[]"); 
    } 
    return 0; 
} 

Dans les deux cas, la sortie est:

a = [1,2,3] //of type int a[] 
b = [5,7,8] //of type int b[] 

EDIT modifié la deuxième exemple pour donner la sortie selon le commentaire récent de OP ci-dessus.

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

int main(void) { 
    char c[] = "[1,2,3][5,7,8]"; 
    char *tok = NULL; 
    char identifier = 'a'; 

    tok = strtok(c, "[]"); 
    while(tok != NULL) { 
     printf("int %c[] = { %s };\n", identifier, tok, identifier); 
     identifier++; 
     tok = strtok(NULL, "[]"); 
    } 
    return 0; 
} 

sortie du programme:

int a[] = { 1,2,3 }; 
int b[] = { 5,7,8 }; 
+0

@ user3213116 J'ai modifié cette réponse suite à votre commentaire récent sur la sortie requise. –

0

Si vous convertissez une chaîne de chiffres de caractères à un tableau de valeurs entières, un caractère par valeur (ou de permettre à un - avant un chiffre de caractères pour indiquer une valeur négative pour votre tableau), vous feriez peut-être mieux d'écrire une fonction simple pour parcourir la chaîne et effectuer vos conversions manuellement.

Un exemple utilisant l'indexation de la chaîne de caractères pourrait être écrit comme suit. Vous pourriez facilement changer les notations d'index de tableau en notation de pointeur qui est plus intuitive à certains.

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

size_t str2arr (char *d, size_t max, char *s, size_t *ofs); 

int main (int argc, char **argv) { 

    char c[] = "[1,2,3][5,7,8]"; 
    char *p = argc > 1 ? argv[1] : c; 
    size_t i, offset = 0, na = 0, nb = 0, nchr = strlen (p); 
    char a[nchr], b[nchr]; 

    memset (a, 0, nchr * sizeof *a); /* zero each VLA */ 
    memset (b, 0, nchr * sizeof *b); 

    na = str2arr (a, nchr, p, &offset);   /* convert first segment */ 
    nb = str2arr (b, nchr, p + offset, &offset); /* convert second segment */ 

    for (i = 0; i < na; i++)      /* output results */ 
     printf (" a[%2zu] : % d\n", i, a[i]); 
    putchar ('\n'); 

    for (i = 0; i < nb; i++) 
     printf (" b[%2zu] : % d\n", i, b[i]); 
    putchar ('\n'); 

    return 0; 
} 

/** convert a string of characters to an array of values 
* including accounting for negative values. the destination 
* index `di` returns the number of characters conversions, the 
* offset of the next segment within 's' is updated in pointer 'ofs' 
*/ 
size_t str2arr (char *d, size_t max, char *s, size_t *ofs) 
{ 
    if (!d || !s || !*s) return 0; /* validate input */ 
    size_t di = 0, neg = 0; 
    register size_t si = 0; 

    for (; di < max && s[si]; si++, di++) {  /* for each character */ 
     if (s[si] == ']') break; 
     while (s[si] && (s[si] < '0' || ('9' < s[si]))) { /* if not digit */ 
      if (s[si] == '-') neg = 1;   /* if '-' sign, set flag */ 
      else neg = 0;    /* clear if not last before digit */ 
      si++; 
     } 
     if (!s[si]) break;     /* validate not end of string */ 
     d[di] = neg ? -(s[si] - '0') : s[si] - '0'; /* convert to digit */ 
     neg = 0;          /* reset flag */ 
    } 

    *ofs = si + 1; /* update offset before return */ 

    return di;  /* return number of conversions */ 
} 

Exemple d'utilisation/sortie

$ ./bin/str2arr 
a[ 0] : 1 
a[ 1] : 2 
a[ 2] : 3 

b[ 0] : 5 
b[ 1] : 7 
b[ 2] : 8 

$ ./bin/str2arr "[1,2,3,4][5,6,-5,7,-1,8,9,2]" 
a[ 0] : 1 
a[ 1] : 2 
a[ 2] : 3 
a[ 3] : 4 

b[ 0] : 5 
b[ 1] : 6 
b[ 2] : -5 
b[ 3] : 7 
b[ 4] : -1 
b[ 5] : 8 
b[ 6] : 9 
b[ 7] : 2 

Regardez-le, comparer cette approche aux autres réponses. En C, vous avez autant de contrôle sur la façon dont vous analysez les données que vous voulez exercer. Si vous n'avez pas besoin de gérer valeurs négatives, alors la mise en œuvre est beaucoup plus simple. Faites moi savoir si vous avez des questions.