Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

SWITCH DE STRINGS (C++)


Information sur la source

Catégorie :Astuces Classé sous : switch, strings, char, strcmp, arguments Niveau : Débutant Date de création : 15/08/2006 Date de mise à jour : 15/08/2006 15:49:29 Vu : 15 160

Note :
Aucune note

Commentaire sur cette source (7)
Ajouter un commentaire et/ou une note


Description

J'ai eu un jour une idée pour "switcher" les strings, ce qui est impossible en c ou c++. Faire des strcmp à tout bout de champ, ça ne m'intéressait pas pour créer un code bien espacé et compréhensible.

Pour me rapprocher des switchs, j'ai décider de faire une fonction à arguments illimités qui renvoie la position de l'argument qui répond au "switch". La fonction s_() effectue tous les strcmp un par un avant que la valeur renvoyée passe au switch.

Voilà ce que ça donne concrètement :
 

Source

  • /********************
  • * Switch de string *
  • * par ordiman85 *
  • ********************/
  • #include <conio.h>
  • #include <stdio.h>
  • #include <string.h>
  • // char* str est la string à "switcher"
  • // IMPORTANT !! Mettre 0 comme dernier argument !
  • #ifdef __cplusplus
  • // Fonction pour C++
  • unsigned int s_(char* str, ...)
  • {
  • unsigned int i = 0;
  • while (*(++i+&str) != 0)
  • if (strcmp(str, (char*)*(&str+i)) == 0)
  • return i;
  • return 0;
  • }
  • #else
  • // Fonction pour le langage C
  • unsigned int s_(char* str, char* cmp[])
  • {
  • unsigned int i = 0;
  • while (cmp[i] != 0) {
  • if (strcmp(str, cmp[i]) == 0)
  • return i+1;
  • i++;
  • }
  • return 0;
  • }
  • #endif
  • // Fonction principale
  • int main()
  • {
  • printf("Test du switch de strings :\r\n");
  • // La string à tester est "switch", sa position est 4
  • char* String = "switch";
  • // On récupère un entier qui correspond à la position de la string identifiée
  • // Méthode 1 (C++)
  • #ifdef __cplusplus
  • unsigned int id = s_(String, "Hello", "world", "!", "switch", "strings", 0);
  • #else // Méthode 2 (C)
  • char* comp[] = {"Hello", "world", "!", "switch", "strings", 0};
  • unsigned int id = s_(String, comp);
  • #endif
  • // Le switch
  • switch (id)
  • {
  • case 1: // "Hello"
  • printf("%d. Hello", id);
  • break;
  • case 2: // "world"
  • printf("%d. world", id);
  • break;
  • case 3: // "!"
  • printf("%d. !", id);
  • break;
  • case 4: // "switch"
  • printf("%d. switch", id);
  • break;
  • case 5: // "strings"
  • printf("%d. strings", id);
  • break;
  • default: // Pas identifié, id = 0
  • printf("Pas dans la liste (%d)", id);
  • break;
  • }
  • // Pause et fin
  • getch();
  • return 0;
  • }
/********************
 * Switch de string *
 *  par ordiman85   *
 ********************/

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


// char* str est la string à "switcher"
// IMPORTANT !! Mettre 0 comme dernier argument !

#ifdef __cplusplus

// Fonction pour C++
unsigned int s_(char* str, ...)
{
  unsigned int i = 0;
  while (*(++i+&str) != 0)
    if (strcmp(str, (char*)*(&str+i)) == 0)
      return i;
  return 0;
}

#else

// Fonction pour le langage C
unsigned int s_(char* str, char* cmp[])
{
  unsigned int i = 0;
  while (cmp[i] != 0) {
    if (strcmp(str, cmp[i]) == 0)
      return i+1;
    i++;
  }
  return 0;
}

#endif

// Fonction principale
int main()
{
  printf("Test du switch de strings :\r\n");
  // La string à tester est "switch", sa position est 4
  char* String = "switch";

  // On récupère un entier qui correspond à la position de la string identifiée
  
  // Méthode 1 (C++)
  #ifdef __cplusplus

    unsigned int id = s_(String, "Hello", "world", "!", "switch", "strings", 0);

  #else // Méthode 2 (C)

    char* comp[] = {"Hello", "world", "!", "switch", "strings", 0};
    unsigned int id = s_(String, comp);

  #endif

  // Le switch
  switch (id)
  {
    case 1: // "Hello"
      printf("%d. Hello", id);
      break;
    case 2: // "world"
      printf("%d. world", id);
      break;
    case 3: // "!"
      printf("%d. !", id);
      break;
    case 4: // "switch"
      printf("%d. switch", id);
      break;
    case 5: // "strings"
      printf("%d. strings", id);
      break;
    default: // Pas identifié, id = 0
      printf("Pas dans la liste (%d)", id);
      break;
  }

  // Pause et fin
  getch();
  return 0;
}

Conclusion

J'ai réussi à adapter la fonction en C mais elle ne supporte pas les arguments illimités (il faut un tableau comme 2ème argument)

IMPORTANT : mettez 0 comme dernier argument !

@+
 

Historique

15 août 2006 15:49:29 :
Adaptation pour le langage C et simplification de quelques trucs

Commentaires et avis

signaler à un administrateur
Commentaire de luhtor le 15/08/2006 18:07:09

En C++, on peut faire ca plus proprement (à mon gout). En fait, on créer une classe qui encapsule un type énuméré (du style de ca: http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4001/) mais qui permet au passage la conversion indice<=>string.

Toute facon, en C++, je vois pas pk on irait utiliser des (char*).

signaler à un administrateur
Commentaire de NitRic le 24/08/2006 21:30:53

« J'ai réussi à adapter la fonction en C mais elle ne supporte pas les arguments illimités (il faut un tableau comme 2ème argument) »

google.com stdarg.h

faut apprendre le langage avant de l'utiliser ...

signaler à un administrateur
Commentaire de verdy_p le 18/02/2007 22:00:44

une autre façon de faire est de convertir les strings non modifiables avec une classe de hachage, qui permet ensuite de les comparer directement par leur seul pointeur ou par un entier numérique associé. Dans Windows, on a une API pour ça: CreateAtom() pour utiliser une table de hachage globale pour le système (ou pour l'aplication, le système prenant en charge les transferts d'atomes d'une table de hachage à l'autre). Voir aussi la fonction qui crée une classe de fenêtre selon le même principe, ou les nombreuses autres tables de hachage du système pour les noms de modules (en retour de la conversion de chaine, on obtient un HANDLE entier.
Evidemment on peut avoir des entrées de hachage créées dynamiquement pour lesquelles on ne sait pas quelle sera la valeur de Handle retournée, mais rien n'interdit de créer une table de hachage dont les premières entrées sont prérenseignées, et dont on connait à l'avance la valeur de handle sous forme d'un entier utilisable dans un switch, et on traite les autres valeurs de hachage dans le switch avec "default:" et en les comparant avec ==

signaler à un administrateur
Commentaire de verdy_p le 18/02/2007 22:04:24

Juste en passant, c'est une très mauvaise idée de déclarer une variable avec le nom générique "String" (qui ressemble à un nom de classe si on fait du C++)
les variables locales devraient commencer par une minuscule, mais "string" est aussi un type standard dans les librairies C++.

Bref utilise "chaine" ou "str" ou "s", ou "nomUtilisateur" avec un nom parlant associé à ce que représente la variable si la fonction manipule beaucoup de variables...

signaler à un administrateur
Commentaire de schlebe le 13/08/2008 11:14:39

Bonjour.

j'utilise une autre technique qui me semble plus efficace, surtout pour la lisibilité du code basée sur l'utilisation de MACRO (#define)

exemple:

#define EVALUATE(s) \
    {\
    string sEvaluate = s;\
    if (false);

#define WHEN(s) \
    else\
    if (sEvaluate == s)
    
#define WhenOTHER \
    else

#define EndEVALUATE \
    }

EVALUATE(sNom)
WHEN("Bernard") cSexe = "M";
WHEN("Chantal") cSexe = "F";
WHEN("Lucien")  cSexe = "M";
WhenOTHER
    {
    cSexe = "?";
    }
EndEVALUATE

Cette technique rend le code plus lisible que l'imbrication de if.
L'instruction EndEVALUATE est également plus explicite que le caractère }.
Il faut cependant remarquer que les blocs WHEN sont totalement séparés et que l'instruction EVALUATE ne peut pas contenir d'instruction "break".
Le nom de la variable locale créée à l'intérieur du bloc annonyme ne peut pas être passé
comme paramètre au risque de perturber l'ensemble.

J'utilise la même technique pour l'instruction SWITCH afin d'éviter un décalage superflu dans l'intruction "case" liée à l'instruction "switch" standard du C/C++.

#define SWITCH(s) \
    switch (s)\
        {

#define EndSWITCH \
        }

exemple:

            SWITCH(sText[0])
            case ',':
                {
                iCode = OP_COMMA;
                bFirstEqual = true;
                break;
                }
            case '(':
                {
                iCode = OP_PAR_OPEN;
                bInFunction = false;
                break;
                }
            case ';': iCode = OP_POINT_VIRGULE;   break;
            case ':': iCode = OP_DOUBLE_POINT;    break;
            case ')': iCode = OP_PAR_CLOSE;       break;
            case '{': iCode = OP_ACCOLADE_OPEN;   break;
            case '}': iCode = OP_ACCOLADE_CLOSE;  break;
            case '[': iCode = OP_SEGMENT_OPEN;    break;
            case ']': iCode = OP_SEGMENT_CLOSE;   break;
            case '.': iCode = OP_POINT;           break;
            EndSWITCH

J'aime également bien la solution de hachage mais elle requiert une organisation plus complexe.

signaler à un administrateur
Commentaire de schlebe le 13/08/2008 11:51:36

voici une autre MACRO qui permet l'instruction BREAK

//******************************************************
//* SELECT
//******************************************************

#define SELECT(s) \
    do {\
    string sEvaluate = s;
    bool bFind = false;\

#define CASE(s) \
    if (bFind = (bFind || (sEvaluate.compare(s) == 0)))\

#define CaseOTHER \

#define EndSELECT \
    } while(false);

string sNom = "Bernard";
char cSexe;

SELECT(sNom)
CASE("Lucien");
CASE("Bernard");
CASE("Marc")
    {
    cSexe = 'M';
    break;
    }
CASE("Chantal");
CASE("Marie");
CASE("Colette")
    {
    cSexe = 'F';
    break;
    }
CaseOTHER
    {
    cSexe = '?';
    }
EndSELECT

Attention, lorsqu'une comparaison est bonne mais que le code est exécuté dans un autre bloc, il faut suffixer l'instruction CASE() du caractère ';'.

Remarque: la méthode "compare" est utilisée pour comparer un objet string et un string literal; ce qui n'était pas le cas dans le message précédent.
La même comparaison avec l'opérateur == en Visual C++ 2008 semble ne pas fonctionner.

A+

signaler à un administrateur
Commentaire de verdy_p le 01/10/2008 15:50:14

"J'utilise la même technique pour l'instruction SWITCH afin d'éviter un décalage superflu dans l'intruction "case" liée à l'instruction "switch" standard du C/C++."

Voila le genre de macros complètement inutiles qui ne résolvent rien du tout! Si c'est pour une raison d'indentation des accolades, c'est une mauvaise raison! Change d'éditeur de texte contre un qui accepte tes préférences d'indentation (dans mon cas, les "case" sont indentés au même niveau que le "switch" et l'accolade de fermeture par défaut dans tous mes projets (C, C++, C#, PHP, ou Java) mais je n'utilise pas ce genre de macros qui ont de gros inconvénients:
- ces macros sont encore plus longues à taper que la syntaxe originale
- elles dissimulent la syntaxe et introduit un niveau de complexité supplémentaire au code. Une macro ne doit se justifier que si cela simplifie à la fois la lecture et la compréhension du code, et facilite son écriture en évitant de commettre des erreurs subtiles ou des oublis de cas.
- elles cassent les outils de gestion de code, bloquent les replis de blocs dans les bons éditeurs.
On ne règle pas les questions d'indentation de code, qui sont largement des questions de préférences personnelles, avec des macros qui justement n'interagissent pas bien du tout avec la syntaxe du langage (passez un indenteur automatique sur votre code, il ressortira illisible!)
Certains n'aiment pas les indenteurs automatiques, pourtant c'est un gain de temps précieux pour modifier ou restructurer le code tout en assurant de maintenir sa lisibilité (l'indentation à la main est souvent pleine d'erreurs!) et sa maintenabilité.
Bref, gardez les accolades et point-virgules qui sont essentiels à la structure même du langage, hors des macros. Les macros sont fortement déconseillées dans les langages objets car elles sont totalement stupides en terme de typage, et généricité, et en terme d'espace de nommage (rique de collisions). En C++, ce qui les remplace avantageusement chaque fois que possible sont:
- les déclarateurs "enum", et "static const"
- les méthodes et fonctions inline
- les templates
Les macros cela reste de la vieille artillerie pour vieux code en C difficile à maintenir. Gardez quelques macros uniquement pour la compilation conditionnelle (code de débogage, ou code spécifique pour un système lors du portage et l'intégration, à masquer pour les autres plateformes): ces macros devraient n'être que des constantes. (Pas étonnant qu'en C# ou Java, les macros ont été proscrites: il n'y a plus de portage à faire, la machine étant totalement virtualisée par le langage lui-même et ses librairies standards; le reste de la compilation conditionnelle est pris en charge par le chargeur de code et l'éditeur de lien à l'exécution, ainsi que le compilateur/optimiseur JIT, le code n'a plus à être masqué et peut être vérifié avec un seul modèle pour toutes les plateformes, le code "superflu" n'affectant alors pas les performances puisqu'il est éliminé automatiquement si inutilisé).

Dernier point: "l'imbrication de if" dont tu parles est un faux problème. Si on s'en tient à la syntaxe brute du C ou C++, ces "if" successifs sont en fait articulés par des clauses "else" finales. Les séquences de "else if" sont si fréquentes qu'il suffit de considérer que "else if" forme un seul mot clé qui n'interromp pas l'instruction "if" en cours. J'indente toujours ces séquences ainsi:
if (test1) {
   ...
} else if (test2) {
   ...
} else if (test 3) {
   ...
} else if (test 4) {
   ...
}
Pas besoin de rajouter des indentations à l'intérieur d'une clauses "else" pour indenter tout le "if" qui le suit et ses sous-clauses "else" internes.

Enfin dans ton code ci-dessus, je ne vois pas l'intérêt des accolades que tu ajoutes dans certains "case" (ce n'est utile que si tu veux déclarer des variables locales à chaque case sans qu'elles se télescopent mutuellement en terme de type déclaré, d'instanciation, d'initialisation ou de fermeture, mais en général les "switch" qui incluent de telles déclarations locales dans les case deviennent trop longs et les cases devraient faire plutôt appel à des sous-fonctions dans lesquelles ces variables locales seront déclarées et utilisées)

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Problème sur un strcmp... [ par Clonk ] Bonjour,voilà, je dois rechercher dans un fichier si chaque ligne correspond à un masque donné (chaque masque est stocké dans une classe). Voilà comme Switch et char [ par Stoomm ] Bonjour,Si j'ai :char test[10];strcpy (test, "monchar ";Si je souhaite faire un switch : Je fais comment ???switch (test){...}Il aime pas ! Quelqu'un exécuter java avec prog en c [ par Bashi ] Bonjour, j'ai essayé d'utiliser un code c pour exécuter du java sous windows, je le compile avec Digital Mars. Mon fichier java est GPS.java et j'ai u pb pour l'affichage d'un tableau [ par blinix123 ] #include &lt;stdlib.h&gt;#include &lt;iostream.h&gt;#include &lt;stdio.h&gt;#include &lt;string.h&gt; &nbsp; &nbsp; struct cd{&nbsp;char artiste [64]; Utilisation des arguments int argc et char *argv[] [ par christophedlr ] Bonjour à tous,Je voudrais savoir comment faire pour tester si un argument de la ligne de commande est par exemple --help pour afficher l'aide par exe Switch texte [ par lastpixl ] Est-il possible de faire un switch sur du texte ? Mon compilateur me fait une erreur à chaque fois que j'essaie avec une chaine.ca marche avec un char Petit problem avec switch [ par Darkneon ] Salut, Mon but est de faire bouger le curseur a l'ecran avec les fleches et d'afficher une lettre a cette position.J'ai le codde suivant.#include &l char**, pointeur et fonction [ par psykocrash ] Salut,Je bosse sur un petit programme et je butte sur un problème de pointeurs. Voici le code source qui pose problème :--------------------#include & pb de concaténation [ par beatrice84 ] Bonjour à tous !Je suis entrain d'écrire un programme de compression selon la méthode de shannon-fano.J'ai un petit problème car je n'arrive pas à con aidez svp [ par bbmmouha ] jesuis un debutant en c++ et je doit fair un projet de motus et j ai fait ce travail mais il y a un probleme que j ai pas arrivé a le comprendre voila


Nos sponsors

Sondage...

CalendriCode

Octobre 2008
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Logiciels à télécharger sur le même thème :



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel BAÏSE, Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,31 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.