Quel est le meilleur moyen d'inverser des caracteres dans un char

Bonjour,

Voici ce que je dois faire et plus, je vous montre comme je l'ai fais. Je ne pense pas que c'est le meilleur moyene t je souhaitais savoir comment faire.

J'ai cette chaine

2015/09/29

et je dois avoir ca

290915

Je voulais savoir comment ceci simplement sans 20 lignes de code.

Je l'ai fais ainsi

char *dd,*mm,*aa,*an;
char day[6]; // Es-ce posssible de déclarer ainsi char *day;????
int ai = 0;
int a = 0;

aa = strtok("2015/09/29","/");
mm = strtok(NULL,"/");
dd = strtok(NULL,"/");

strncpy(day,dd,sizeof(day));
strncat(day,mm,sizeof(day));

ai = strlen(day); // = 4

// La je ne suis pas certain de bien faire
 for (an=aa; *an; an++)
 {
    // Des le deuxième passage
                 if (a >= 2)
                  {
                    // l'index 4 prend 1
                   // l'index 5 prend 5
                    day[ai++] = *an;   // Incrémente l'index
                  }
                  a++; // Incrémente les passages
                }
// index 6 prend \0
                day[ai]='\0';

Mais on peut pas faire ca plus simplement et sûrement?

Sachante que la variable aa à la valeur de 2015, comment pourrais-je tout simplement suprimer '20' et mettre '15' à l'index 0 et 1

Ainsi, je pourrais finir ainsi

strncat(day,aa,sizeof(day));

'day' pourra etre déclaré ainsi

char day[6]
0:2
1:9
2:0
3:9
4:1
5:5
6:\0

Merci pour vos lumières!

Merci

Et je viens de découvir que je ne peux pas faire avec strtok() car il y a un conflit avec un précédent srtotk()

0,6.141163,46.219817,2015/09/29,21:58:04

J'utilise strtok pour sinder les premieres

char * fix; // => "0,6.141163,46.219817,2015/09/29,21:58:04",","
char *date // => 2015/09/29

// 0 => strtok(fix,",");
// 6.141163 => strtok(NULL,",");
// 46.219817 => strtok(NULL,",");
// 2015 => strtok(date,"/");
// 09 => strtok(NULL,"/")
// 29 =>strtok(NULL,"/")

// 21:58:04 => strtok(NULL,",") ICI CA BUG ca c'est la suite de date alors que ca doit etre la suite de fix

Donc je dois trouver un autre moyen qu'avec strtok pour sincer la date

En résumé, comment faire quand j'ai:

20150921

pour avoir au final:

210915

Sans utiliser de strtok()
sachant que le char contenant 2015/09/21 est déclaré ainsi char *cha;

Ou alors tu effaces tout, tu oublies les pointeurs et autres, et tu réalises qu'une chaîne de caractères n'est rien d'autre qu'un tableau de char dont le dernier a forcément la valeur 0.

void afficher(char chaine[], char nom_chaine[])
{
  Serial.print("La chaine ");
  Serial.print(nom_chaine);
  Serial.print(" contient >");
  Serial.print(chaine);
  Serial.println('<');
}


void setup() {
  Serial.begin(9600);

  char source[] = "2015/09/28";
  afficher(source,"source");

  char cible[7];
  cible[0] = source[8];
  cible[1] = source[9];
  cible[2] = source[5];
  cible[3] = source[6];
  cible[4] = source[2];
  cible[5] = source[3];
  cible[6] = (char) 0;
  afficher(cible,"cible");

  char fix[] = "0,6.141163,46.219817,2015/09/29,21:58:04";
  afficher(fix,"fix");
  
  int i = 0;
  while ((fix[i] != '/' && fix[i] != (char) 0)) i++;
  if (fix[i] == '/' && i > 1) {
    cible[0] = fix[i+4];
    cible[1] = fix[i+5];
    cible[2] = fix[i+1];
    cible[3] = fix[i+2];
    cible[4] = fix[i-2];
    cible[5] = fix[i-1];
    cible[6] = (char) 0;
  }
  else {
    cible[0] = (char) 0;
  }
  afficher(cible,"cible");
}

void loop() {
}

Ca ne dort pas, à cette heure ci, à Genève?

Bonjour,

C'est très simple.

char *dd,*mm,*aa;
char day[7];

aa = strtok("2015/09/29","/");
mm = strtok(NULL,"/");
dd = strtok(NULL,"/");

strncpy(day,dd,2);
strncat(day,mm,2);
strncat(day,aa+2,2); // ajoute l'année sur 2 chiffres

Remarques:

  • on doit déclarer day[7] et non pas day[6] car il y a 6 caractères plus le 0 de fin
  • c'est très bien d'avoir utilisé strncpy et strncat au lieu de strcpy et strcat pour éviter le débordement de day, mais il serait bon de tester le retour de strtok pour vérifier que la chaîne analysée a bien le format attendu.
  • dans strncpy et strncat, le 3eme argument n'est pas la taille de la destination, mais le nombre maxi de caractères à copier (ici 2)

pierrot10:
Et je viens de découvir que je ne peux pas faire avec strtok() car il y a un conflit avec un précédent srtotk()

Je te renvoie au lien de ma réponse précedente. Tu verras qu'il y est dit qu'il faut utiliser strtok_r() à la place de strtok() lorsqu'on veut faire des appels concurrents ou récursifs.

J'abonde dans le sens de fdufnews, mais ici il ne devrait pas y avoir de problème. Dans ton post pécédent tu avais découpé la chaine principale en sous chaine. Dans un deuxième temps tu traites chacune des sous chaine.

Hello

Merciii pour vos observations

  • dans strncpy et strncat, le 3eme argument n'est pas la taille de la destination, mais le nombre maxi de caractères à copier (ici 2)

Ca c'est super, j'étais en effet tout faux!!!

Merci fdufnews. Je t'avoir utiliser pour la premiere fois strtok() et ne pas avoir trop compris strtok_r(). Je vais regarder ceci plus en profondeur de suite.

Merci

Bonjour,
Je pense que je métrise pas strtok_r car ca ne marche pas.
Je dois mal m'y prendre avec le troiseme parametre.

Voici mon code avec mes commentaires.
Je pense que je fais faux avec saveptr1 et saveptr2. Quelle valeur lui donner?

        #ifdef DEBUG_GPS
          sprintln((char *)comm_buf); // Affiche : 0,6.141163,46.219819,2015/09/25,19:15:20
        #endif

        
        cha = strtok((char *)comm_buf,",");
//sprint(F("First index of strtok 1:"));sprintln(cha);
        
        if(atoi(cha) > 0)
        {
          #ifdef DEBUG_GPS
            Serial.print(F("Loc ERR:"));
            Serial.println(atoi(cha));
          #endif

          strncpy(fix,strtok(fix,","),FIXSIZE);
          strncat(fix,",,V,,,,,,,,,,",FIXSIZE);
          result = -1;
        }
        else
        {
        
          c = 0;
          d = 0;
          h = 0;

          do
          {
            Serial.println(c); // N?afffiche rien
            switch(c){
              case 0:
                cha = strtok_r(NULL,",",&saveptr1); // Affiche : 6.141163
                lon = cha;
                break;

              case 1:
                cha = strtok_r(NULL,",",&saveptr1); // Affiche : 46.219819
                lat = cha;
                break;

              case 2:
                cha = strtok_r(NULL,",",&saveptr1); // Affiche : 2015/09/25
                // 2015/09/20
    Serial.println(cha);

      
                aa = strtok_r(cha,"/",&saveptr2); // Affiche : 2015
                mm = strtok_r(NULL,"/",&saveptr2); // affiche : 09
                dd = strtok_r(NULL,"/",&saveptr2); // Affiche : 25

// ICI RIEN N'ETS AFFICHE CAR JE PENSE QUE cha RESTE NULL. DONC IL SORT DE LA BOUCLE

Serial.println(F("aa"));
Serial.println(aa);
Serial.println(F("mm"));
Serial.println(mm);
Serial.println(F("dd"));
Serial.println(dd);

                strncpy(day,dd,2);
                strncat(day,mm,2);
                strncat(day,aa+2,2); 

Serial.println(day); // doit afficher : 250915
Serial.println(strlen(day));
Serial.println(sizeof(day));



                break;

              case 3:
// Case 3 sera corriger en fonction de case 2
                cha = strtok_r(NULL,",",&saveptr1); // Affiche : 19:15:20
                for (hr=cha; *hr; hr++)
                {
                  if (*hr!=':' && *hr!='\n' && *hr!='\r')
                  {
      //      Serial.print(*hr);
                    hour[h++] = *hr;
                  }
                }
                hour[h]='\0'; // affiche 
                
                break;

              case 4:
                cha = strtok_r(NULL,",",&saveptr1);
                #ifdef DEBUG
                  // sprint(F("?:"));
                  // sprintln(cha);
                #endif
                break;

              default:
                cha = strtok_r(NULL,",",&saveptr1);
                #ifdef DEBUG_GPS
                  Serial.print(F("Def : "));
                  sprintln(cha);
                #endif
            } // End switch
            c++;
          }while(cha != NULL);
       

        

          strncpy(fix,strtok(fix,","),FIXSIZE);

          strncat(fix,",",1);
          strncat(fix,hour,4);      // Hour
          strncat(fix,".00,V,",6);     // Status
          strncat(fix,lat,FIXLEN);       // lat
          strncat(fix,",,",2);      // N/S
          strncat(fix,lon,FIXLEN);       // lon
          strncat(fix,",,,,",4);     // E/W, Speed, Course,
          strncat(fix,day,6);       // Date
          strncat(fix,",,,",3);     // MAgetisma, Mode, Checksom

          #ifdef DEBUG_GPS
            sprint(F("fix2:\t\t\t\t"));
            sprintln(fix);  // Affiche : 0,6.141163,46.219819,250915,191520
            Serial.println(strlen(fix));
          #endif

          result = 1;
        }
}

Merci pour vos lumières concernant srttok_r()!

Bonjour,

Ton premier
cha = strtok((char *)comm_buf,",");
doit bien sur être un
cha = strtok_r((char *)comm_buf,",",&saveptr1);
sinon tu fais des appels à strtok_r uniquement avec l'adresse NULL

pour le debug met un Serial.println(cha) au début de ta boucle

strtok() est une fonction qui peut être pratique, mais elle a deux contraintes d'utilisation.

Tout d'abord, elle intègre une variable statique (un pointeur) qui lui permet de conserver son contexte entre deux appels.
Cela lui permet de poursuivre là où elle en était sur un appel de type strtok(NULL,"/");
La conséquence est que cette fonction n'est pas réentrante. C'est-à-dire que l'on ne peut pas l'utiliser pour analyser deux chaînes en parallèle.

L'autre contrainte, c'est qu'au fur et à mesure du découpage de la chaîne, les séparateurs sont remplacés par un caractère nul dans la RAM. Cette fonction altère le contenu de la chaîne source.
Pour être tranquille, il faut commencer par recopier la chaîne source dans un buffer de travail, puis exécuter strtok() sur ce buffer.

Du coup, personnellement je préfère m'en passer.
D'autant que la plupart du temps, il n'est pas très compliqué de fabriquer sa propre fonction qui balaie un par un les caractères de la chaîne, selon le besoin (voir exemple de code que j'ai mis plus haut).

Je vois que tu utilises des fonctions sur les chaînes (dont strtok) et des variables de type pointeur, et que dans le même temps tu t'interroges sur l'utilisation d'un simple tableau de char ou bien tu oublies le caractère nul terminal.
C'est un peu comme vouloir courir avant de savoir marcher : cela peut être méritoire, on peut y trouver un certain plaisir intellectuel, mais c'est quand même un peu risqué. :stuck_out_tongue:

Utiliser un char *dd, le valoriser via une fonction sur les chaînes, pour finir par un strncpy(day,dd,2) n'est pas ce que je conseillerais à un débutant.

A la place, une simple boucle sur la chaine source pour déterminer le rang du premier caractère qui t'intéresse, puis day[0] = source[rang]; day[1] = source[rang+1] me semble beaucoup plus accessible.

Et en plus, c'est formateur.
Une fois qu'on maîtrise la manipulation de chaîne, on comprend comment c'est organisé dans la RAM et (seulement) à partir de là on peut utiliser des fonctions toutes faites et des pointeurs dans tous les sens.

Salut Kamill,

Oui j'ai vu au meme moment ou tu m'a répondu.

Que veux tu dire par

sinon tu fais des appels à strtok_r uniquement avec l'adresse NULL

Es-ce juste de faire ainsi.

J'ai corrigé donc l'erreur que tu as relevé et ca fonctionne bien mieux!!!

Mais il y a un truc qui me rend fou!

Voci mon code que j'ai corrigé. Tu observera que j'ai volontairement inversé le jour et la date

210915 => 092115

En fait la chaine que traite fini par l'heure et je pense qu'il y a un \0 apres les seconde. Et je pense que ca cause mon deuxieme problem et qui me rend fou

Voici donc le code

      #ifdef DEBUG_GPS
          sprintln((char *)comm_buf);
        #endif

        
        // 0,6.141163,46.219819,2015/09/25,19:15:20
        cha = strtok_r((char *)comm_buf,",",&saveptr1);
//sprint(F("First index of strtok 1:"));sprintln(cha);
        
        if(atoi(cha) > 0)
        {
          #ifdef DEBUG_GPS
            Serial.print(F("Loc ERR:"));
            Serial.println(atoi(cha));
          #endif

          strncpy(fix,strtok(fix,","),FIXSIZE);
          strncat(fix,",,V,,,,,,,,,,",FIXSIZE);
          result = -1;
        }
        else
        {
        
          c = 0;
          d = 0;
          h = 0;
         // ai = 4;

          do
          {
            Serial.print(F("cha: "));
            Serial.println(cha);
            
            switch(c){
              case 0:
                cha = strtok_r(NULL,",",&saveptr1);
                lon = cha;
           //     Serial.println(lon);
                break;

              case 1:
                cha = strtok_r(NULL,",",&saveptr1);
                lat = cha;
           //     Serial.println(lat);
                break;

              case 2:
                cha = strtok_r(NULL,",",&saveptr1);

                aa = strtok_r(cha,"/",&saveptr2);
                mm = strtok_r(NULL,"/",&saveptr2);
                dd = strtok_r(NULL,"/",&saveptr2);

                Serial.println(strlen(dd));
                Serial.print(F("aa:"));
                Serial.println(aa);
                Serial.print(F("mm:"));
                Serial.println(mm);
                Serial.print(F("dd:"));
                Serial.println(dd);

                
                strncpy(day,mm,2);
                strncat(day,dd,2);
                strncat(day,aa+2,2);

                Serial.println(day);
                Serial.println(strlen(day));
                Serial.println(sizeof(day));



                break;

              case 3:
                cha = strtok_r(NULL,",",&saveptr1);
                for (hr=cha; *hr; hr++)
                {
                  if (*hr!=':' && *hr!='\n' && *hr!='\r')
                  {
      //      Serial.print(*hr);
                    hour[h++] = *hr;
                  }
                }
                hour[h]='\0';
                
                break;

              case 4:
                cha = strtok_r(NULL,",",&saveptr1);
                #ifdef DEBUG
                  // sprint(F("?:"));
                  // sprintln(cha);
                #endif
                break;

              default:
                cha = strtok_r(NULL,",",&saveptr1);
                #ifdef DEBUG_GPS
                  Serial.print(F("Def : "));
                  sprintln(cha);
                #endif
            } // End switch
            c++;
          }while(cha != NULL);
       
          /*
          #ifdef DEBUG_GPS
            sprint(F("Lon:\t\t\t\t"));
            sprintln(lon);
            sprint(F("lat:\t\t\t\t"));
            sprintln(lat);
            sprint(F("Day:\t\t\t\t"));
            sprintln(day);
            sprint(F("Hour:\t\t\t\t"));
            sprintln(hour);
          #endif
          */
        

          strncpy(fix,strtok(fix,","),FIXSIZE);

          strncat(fix,",",1);
          strncat(fix,hour,4);      // Hour
          strncat(fix,".00,V,",6);     // Status
          strncat(fix,lat,FIXLEN);       // lat
          strncat(fix,",,",2);      // N/S
          strncat(fix,lon,FIXLEN);       // lon
          strncat(fix,",,,,",4);     // E/W, Speed, Course,
          strncat(fix,day,6);       // Date
          strncat(fix,",,,",3);     // MAgetisma, Mode, Checksom

          #ifdef DEBUG_GPS
            sprint(F("fix2:\t\t\t\t"));
            sprintln(fix);
            Serial.println(strlen(fix));
          #endif

          result = 1;
        }
}

et voii ce que ca affiche:

0,6.141164,46.219818,2015/09/30,16:46:23

cha: 0
cha: 6.141164
cha: 46.219818
2
aa:2015
mm:09
dd:30
09^3015
7
7
cha: 2015
cha: 16:46:23

fix2: cid=0&mnc=00&mcc=000&lac=0&gprmc=$GPRMC,1646.00,V,46.219818,,6.141164,,,,09^301,,,
82

tu voix il y a un mauvais caratere entre le mois et le jour?
Ce mauvais caracter ne se voit pas en HTML. Je le remplace par un ^

09^3015

Si je remets comment avant

strncpy(day,dd,2);
strncat(day,mm,2);
strncat(day,aa+2,2);

30^0915

Ben ca fait la meme chose. Une fois j'ai vu un 'q' avec deux mauvais caracrteres, entre le jour et le mois.

30^q^0915

Je n'arrive pas a comprendre pourquoi j'ai ce mauvais caractere. Pourtant, j'utilise strncat() et je defini 2 caracteres. Donc si à la fin, il y a un \0, il ne devrait pas le prendre??? non?

Merci bricolau pour ton explication

Le problème c'est que dans cette chaine de caratere

0,6.141164,46.219818,2015/09/30,16:46:23

Sa longueur peut changer car la latitude et la longitude peuvent avoir plus ou moins de caracteres

Je me sens un peu plus perdu car je pensais trouver la solution avec strtoK_r() :confused: :o

Mais y a pas plus simple de tranformer

0,6.141164,46.219818,2015/09/30,16:46:23

et ca?

0,6.141164,46.219818,300915,164623

Je devrai de toute maniere sinder encore cette chaine pour mettre lat, lon, la date et l'heure dans ses propres variable car ces variable vont me permetre de contruire une URL

Le '0,' , j'en ai pas besoin..

pierrot10:
Je n'arrive pas a comprendre pourquoi j'ai ce mauvais caractere. Pourtant, j'utilise strncat() et je defini 2 caracteres. Donc si à la fin, il y a un \0, il ne devrait pas le prendre??? non?

Le \0 est le caractère de fin de chaine, donc tu ne le vois jamais lorsque tu affiches la chaine.
Je ne vois pas d'ou vient ce caractère bizarre.
J'essaie de reproduire le problème dès que je rentre chez moi.

C'est super Kamill. Ca m'aiderai beaucoup. Je suis toujours en train d'essayer différement :sweat_smile:

pierrot10:
Merci bricoleau pour ton explication

Le problème c'est que dans cette chaine de caratere0,6.141164,46.219818,2015/09/30,16:46:23Sa longueur peut changer car la latitude et la longitude peuvent avoir plus ou moins de caracteres

Ben justement, regarde au moins les quelques lignes de code que je t'ai données.
A quoi ça sert que Ducros il se décarcasse ?

Allez, je les remets ici

  char fix[] = "0,6.141163,46.219817,2015/09/29,21:58:04";
  char day[7];
  
  int i = 0;
  while ((fix[i] != '/' && fix[i] != (char) 0)) i++;
  if (fix[i] == '/' && i > 1) {
    day[0] = fix[i+4];
    day[1] = fix[i+5];
    day[2] = fix[i+1];
    day[3] = fix[i+2];
    day[4] = fix[i-2];
    day[5] = fix[i-1];
    day[6] = (char) 0;
  }

Y a pas de pointeur, pas de strtok ni strncpy.
Mais ça marche, même avec une position de la date variable, puisqu'on commence par chercher le rang du premier caractère / de la chaîne.

Je n'arrive pas a comprendre pourquoi j'ai ce mauvais caractere.

Je crois que j'ai compris le problème: le nombre de caractère dans strncpy doit inclure le 0 de fin il faut donc faire:

          strncpy(day, mm, 3);
          strncat(day, dd,3);
          strncat(day, aa + 2,3);

Je vous remercie à tous pour votre aide!
Je suis dans le train et je ne peux pas copier mon code mais j'ai résolu mon problème. Du moins j'espère de ne pas voir de surprise.

J'ai fait mon truc en trois partie.

D'abord j'utilise strtok() (sans le _r) pour scinder la premier grande chaîne en gardant l'heure et la date.

Puis une fois que je suis sorti de la boucle do (avant je faisais tout avant de sortir de la première boucle), je refais un ´do' et j'utilise strtok pour la date. Je sors de la boucle et je recommance pour l'heure.

Je suis arrivé à mon but mais ça fait vraiment beaucoup de code.

Je vais comme même regarder vos propositions. J'avais aussi constater la dernière remarque de kamill sans pour autant résoudre mais je vais essayé ceci. Je vais aussi mieux regarder le code de bricolo, car si je peux faire plus lege, c'est mieux.

Je vois que je vais faire face à un autre problème de taille mais que je dois encore vérifier:
Mon GPS me retourne les position en décimal alors que mon sim900 me retourne la triangulation en degré, minute alors qu'openGTS n'accepte que l'un ou l'autre (je dois vérifier encore ceci).
Si tel est le cas , je vais devoir trouver la parade pour qu' arduino envoie tout au serveur, sous le même format! Ouf!!!

Merci pour votre aide!!!!!!