IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Mise en place algo complexe en C#


Sujet :

C#

  1. #21
    Membre du Club
    Inscrit en
    Décembre 2005
    Messages
    172
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 172
    Points : 43
    Points
    43
    Par défaut
    EXpliquez comme cela c'est tout simple.
    Je me lance. Il faudra que je fasse une fonction recursive.
    Je ne passerais pas par une classe mais une simple fonction.

    Je reviens vers toi pour te confirmer si j'ai réussi.

    Merci pour ton aide

  2. #22
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Citation Envoyé par Naruto_kun Voir le message
    Il faudra que je fasse une fonction recursive.
    Je ne passerais pas par une classe mais une simple fonction.
    Je te recommande la récursivité mais si ça te dérange tu peux t'en passer (toute solution récursive peut être réécrite avec une pile).

    En revanche si tu décides de ne pas avoir de classe alors tu devras fournir jusqu'à quatre arguments à certains appels (texte, indice, arguments, booléen pour supprimer l'évaluation). Ça me semble un peu lourd mais bon à ta guise.

  3. #23
    Membre du Club
    Inscrit en
    Décembre 2005
    Messages
    172
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 172
    Points : 43
    Points
    43
    Par défaut
    J'ai des petits soucis dans mon algo avec la récursivité.

    En entrée de ma fonction j'aurais mon expression et un dictionnaire<int,bool> qui contient déjà le boolean permettant de savoir si le champ a été saisi ou non.
    Par exemple :
    j'ai 1,2,3,4 et 5 paramètres alors dans mon dictionnaire j'aurais ceci
    <0,true> car saisie
    <1,true> car saisie
    <2,true> car saisie
    <3,true> car saisie
    <4,false> car non saisie
    Bien evidement il est rempli en fonction des 5 paramètre.

    En plus de ces 2 paramètre qui sont mon expression et le dictionnaire, j'aurais en plus un entier pour la position dans la règle et un autre entier pour la position dans le dico.
    Mon algo change un peu mais j'emmêle les pinceaux au niveau de l'appel récursif à la fonction.

    Voici un morceau de mon algo mais je pense qu'il n'est pas bon :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
     
            protected bool checkRule(string rules, Dictionary<int, bool> groupValids,int positionChaine,int positionDico)
            {
                int len = rules.Length;
                bool resultat = false;
                if (string.IsNullOrEmpty(rules))
                    return true;
     
                foreach (char rule in rules)
                {
                    if (rule == '(')
                    {
                        // Je refais l'appel en incrementant la position dans la chaine
                        resultat = checkRule(rules, groupValids, positionChaine + 1, positionDico);
                    }
     
                    int numRule;
                    int.TryParse(rule.ToString(), out numRule);
                    if (rule >= 1 && rule <= 9)
                    {
                        // Je recupere ma valeur du dictionnaire pour vérifier sa saisi
                        resultat &= groupValids[positionDico];
                        positionDico++;
                        // Je refais l'appel en incrementant la position dans la chaine et la position dans le dico
                        resultat = checkRule(rules, groupValids, positionChaine + 1, positionDico);
                    }
     
     
                    // Il faut que je traite le & et le | ainsi que la parenthèse fermante
                    if (rule == '&')
                        resultat &= checkRule(rules, groupValids, positionChaine + 1, positionDico);
     
                    if (rule == '|')
                        resultat |= checkRule(rules, groupValids, positionChaine + 1, positionDico);
     
                }
     
                //return false;
            }
    je ne suis pas bon et honnêtement je m'arrache un peu les cheveux. Je crois que cette ligne ne devrait pas etre la resultat &= groupValids[positionDico];

    Pourrais tu m'aiguiller?

    Merci

  4. #24
    Membre du Club
    Inscrit en
    Décembre 2005
    Messages
    172
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 172
    Points : 43
    Points
    43
    Par défaut
    De plus, imaginons si un jour j'ai plus de 10 paramètres. Tout cela ne fonctionnera pas car je devrais à un moment données extraire 2 caractères et non plus juste un.

    C'est le bordel

  5. #25
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Pour commencer tu ne dois pas utiliser foreach.

    D'abord parce que la façon dont tu interprètes un caractère dépend du précédent, par exemple "&" est valide après un chiffre mais pas après une parenthèse ouverte. Pour gérer ça avec un foreach il faudrait, pour chaque caractère reconnu, revérifier le caractère précédent. Il est plus simple et plus logique de ne pas avoir de foreach et d'avancer manuellement au fur et à mesure que tu reconnais les caractères : si tu viens de parser l'opérande gauche tu attends ensuite un opérateur et donc tu inséres seulement les instructions pour ce cas. Curieusement c'est ce que tu as fait à l'intérieur du foreach où l'on voit une séquence "opérande gauche - opérateur - opérande".

    Ensuite parce que les appels récursifs font avancer le parsing. Chaque appel à checkRule doit prendre une position de départ de la sous-expression et retourner la position de fin de la sous-expression. Tu l'as compris mais pas mis en oeuvre puisque tu n'utilises pas ton "positionChaine". Pour ça tu peux soit passer positionChaine en "ref", soit ajouter un paramètre de sortie "out", soit renvoyer une paire "position de sortie / résultat". Au passage, parce que tu utilisais foreach plutôt que positionChaine, toutes tes sous-expressions recommençaient du début de la chaîne.

    Commence donc par virer ce foreach et utiliser ton positionChaine, tu y verras plus clair.

  6. #26
    Membre du Club
    Inscrit en
    Décembre 2005
    Messages
    172
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 172
    Points : 43
    Points
    43
    Par défaut
    DonQuiche > J'ai un peu de mal avec la recusivité. J'ai l'impression que mes conditions ne sont pas prises en compte.

    Voici mon code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
     protected bool checkRule(string rules, Dictionary<int, bool> groupValids, int positionChaine, int positionDico)
            {
                int len = rules.Length;
                bool resultat = false;
                if (string.IsNullOrEmpty(rules))
                    return true;
     
                string rule = rules.Substring(positionChaine, 1);
                if (rule == "(")
                {
                    // Je refais l'appel en incrementant la position dans la chaine
                    resultat = checkRule(rules, groupValids, positionChaine + 1, positionDico);
                }
     
                int numRule;
                int.TryParse(rule, out numRule);
                if (numRule >= 1 && numRule <= 9)
                {
                    // Je recupere ma valeur du dictionnaire pour vérifier sa saisi
                    resultat &= groupValids[positionDico];
                    positionDico++;
                    // Je refais l'appel en incrementant la position dans la chaine et la position dans le dico
                    resultat = checkRule(rules, groupValids, positionChaine + 1, positionDico);
                }
     
                // Il faut que je traite le & et le | ainsi que la parenthèse fermante
                if (rule == "&")
                    resultat &= checkRule(rules, groupValids, positionChaine + 1, positionDico);
     
                if (rule == "|")
                    resultat |= checkRule(rules, groupValids, positionChaine + 1, positionDico);
     
                //Tant que l'on est pas à la fin on continue d'avancer
                if (rule == ")" && positionChaine < rules.Length)
                    resultat &= checkRule(rules, groupValids, positionChaine + 1, positionDico);
     
     
                return resultat;
            }
    Il me manque un truc et je ne trouve pas quoi.

  7. #27
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    * Ton principal problème ici est que positionChaine n'est pas modifiée dans l'appel parent : si tu as une opérande de 5 caractères (par exemple (a|b)) alors positionChaine doit être augmentée de 5 caractères au retour. Une solution pour ça est de passer "positionChaine" en "ref" (mot-clé c#) ou d'en faire une variable d'instance. Note aussi qu'avec "ref" tu dois faire l'addition avant de faire l'appel.

    * Ta variable "rule" n'est actuellement jamais modifiée. Tu dois la recalculer chaque fois que tu modifies positionChaine, sans quoi c'est toujours le premier caraactère. Au passage pour son type pas besoin d'une chaîne alors qu'un seul caractère suffirait. Tu pourrais alors utiliser rules[positionChaine] plutôt que ce Substring.



    * Il ne peut pas y avoir de nombre après une parenthèse ouverte. L'opérande gauche est soit un nombre, soit une opération entre parenthèses, pas les deux à la suite. Ton code devrait refléter explicitement ça avec un "if/else" plutôt que de s'appuyer implicitement sur la valeur par défaut pour numRule après TryParse. C'est typiquement le genre de bidouille qui obscurcit le code, complexifie sa lecteur et se transforme en niche à bogue. Écris ton code pour des êtres humains.

    * Dans le même esprit ta gestion de la parenthèse fermée est laxiste: actuellement il autorise des parenthèses fermées en trop. Ça peut encore passer mais bon...

    * Si la récursivité te dérange, passe t-en : utilise une boucle while couplée ) une pile (Stack<bool>) pour stocker les résultats des opérandes gauches.

  8. #28
    Membre du Club
    Inscrit en
    Décembre 2005
    Messages
    172
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 172
    Points : 43
    Points
    43
    Par défaut
    Merci pour ta réponse.

    J'aimerais continuer à utiliser la récursivité car c'est un nouveau concept pour moi et j'aimerais bien le gérer à l'avenir.

    Ensuite tu dis cela:
    * Ton principal problème ici est que positionChaine n'est pas modifiée dans l'appel parent : si tu as une opérande de 5 caractères (par exemple (a|b)) alors positionChaine doit être augmentée de 5 caractères au retour. Une solution pour ça est de passer "positionChaine" en "ref" (mot-clé c#) ou d'en faire une variable d'instance. Note aussi qu'avec "ref" tu dois faire l'addition avant de faire l'appel.
    Ma position chaine est augmenté de 1 à chaque appel. Quand je debug je vois que le caractère change.
    Pourquoi devrait il être augmenté de 5? Je devrais les traiter un par un.
    A moins que tu veuilles que je travaille expression par expression, c'est à dire que je récupère toute règle en parenthèse que j'evalue et ensuite je passe à la suivante.
    Si c'est cela, comment traiter ceci ((a&b) | (c&d)). Il faut que j'analyse le |à un moment donné.


    * Ta variable "rule" n'est actuellement jamais modifiée. Tu dois la recalculer chaque fois que tu modifies positionChaine, sans quoi c'est toujours le premier caraactère. Au passage pour son type pas besoin d'une chaîne alors qu'un seul caractère suffirait. Tu pourrais alors utiliser rules[positionChaine] plutôt que ce Substring.
    Tu as raison j'utiliserais ceci à l'avenir rules[positionChaine]

    je ne saisi pas tout. Désole

  9. #29
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Citation Envoyé par Naruto_kun Voir le message
    Ma position chaine est augmenté de 1 à chaque appel. Quand je debug je vois que le caractère change.
    Ce que tu vois ce sont les variables dans l'appel enfant : ces variables n'ont pas les mêmes valeurs dans l'appel parent. A chaque appel récursif tu crées de nouvelles variables ayant le même nom. Tu peux le vérifier en mode debug : si tu double-cliques sur l'appel parent dans la pile des appels, tu verras que VS t'affiche alors d'autres valeurs pour ces variables et surligne une autre position d'exécution.

    Or, donc, il ne te faut pas des pelletées de "positionChaine" ayant le même nom et des valeurs différentes mais au contraire une seule valeur commune et partagée. Tu peux soit utiliser une variable d'instance, ou alors passer ta variable initiale en "ref", auquel cas tu auras des pelletées de références pointant toutes vers une variable unique.

    Pourquoi devrait il être augmenté de 5? Je devrais les traiter un par un.
    De 5 parce que "(a|b)" mesure cinq caractères. Ton algorithme va incrémenter cinq fois de un, à chaque fois qu'il traitera un nouveau caractère. Ca sera fait automatiquement quand tu passeras ta variable par "ref" ou en instance. Tu n'as pas à changer ton algorithme, tu as déjà un "+1" après chaque caractère.

    je ne saisi pas tout. Désole
    C'est tout à fait normal et tu n'as pas à t'en excuser.
    Il faut bien apprendre un jour et par ailleurs tu ne ménages pas ta peine.

  10. #30
    Membre du Club
    Inscrit en
    Décembre 2005
    Messages
    172
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 172
    Points : 43
    Points
    43
    Par défaut
    J'ai compris pour le ref. Cela signifie que le changement de positionChaine sera prise en compte quelque soit le sous niveau (enfant).
    Par contre, je m'embrouille encore avec cet algo.

    Finalement si je rencontre '(' alors j'incrément positionChaine et je fais appel à checkRule avec positionChaine en ref.

    Par contre si je rencontre une opérande de 1 à 9. Dois je incrémenter positionChaine? Je pense que oui sinon on n'avance pas. j'augmente aussi positionDico.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    * Il ne peut pas y avoir de nombre après une parenthèse ouverte. L'opérande gauche est soit un nombre, soit une opération entre parenthèses, pas les deux à la suite. Ton code devrait refléter explicitement ça avec un "if/else" plutôt que de s'appuyer implicitement sur la valeur par défaut pour numRule après TryParse. C'est typiquement le genre de bidouille qui obscurcit le code, complexifie sa lecteur et se transforme en niche à bogue. Écris ton code pour des êtres humains.
    je dois faire quoi exactement je fais un if sur quel valeur?

    Il faut savoir que la manière dont on construit l'algo, a terme il ne répondra pas à toutes les exigences mais cela on en discutera à la fin si tu veux bien.
    Petit exemple: si j'ai plus de 9 paramètres, mes règles risque de ressembler à ceci ((9&10)|(11&12))
    Je pense que tu as compris ou je veux en venir.

  11. #31
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    * Le test doit porter sur "rule == '('". En gros ton algo doit faire: si parenthèse alors parser sous-expression entre parenthèses, sinon parser nombre. Ca revient simplement à ajouter un bloc else à ton code et y regrouper toute la gestion des nombres.

    * Tu dois incrémenter positionChaine à chaque caractère traité. Donc en rencontrant un chiffre tu dois effectivement incrémenter.


    * Pour gérer les nombres à plusieurs chiffres voici deux solutions:
    a) Ce que moi j'avais fait : une boucle while parcourt tous les chiffres pour les compter (ou trouver l'index du dernier chiffre ou du premier non-chiffre, il y a plusieurs variantes de l'algo). Puis on utilise cette info pour extraire la sous-chaîne du nombre (via Substring) et on passe celle-ci à int.Parse.

    b) On oublie int.Parse et TryParse et on parse manuellement au fil de l'eau : on commence avec une variable nombre = 0 et à chaque chiffre on fait nombre = nombre * 10 + chiffre.

  12. #32
    Membre du Club
    Inscrit en
    Décembre 2005
    Messages
    172
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 172
    Points : 43
    Points
    43
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    protected bool checkRule(string rules, Dictionary<int, bool> groupValids,ref int positionChaine, int positionDico)
            {
                int len = rules.Length;
                bool resultat = false;
                if (string.IsNullOrEmpty(rules))
                    return true;
     
                if (rules[positionChaine] == '(')
                {
                    positionChaine++;
                    // Je refais l'appel en incrementant la position dans la chaine
                    resultat = checkRule(rules, groupValids, ref positionChaine, positionDico);
                }
                else
                {
                    bool ischiffre = true;
                    int chiffre;
                    int positionDeb = positionChaine;
                    while (ischiffre)
                    {
                        if (int.TryParse(rules[positionChaine].ToString(), out chiffre))
                            positionChaine++;
                        else
                            ischiffre = false;
                    }
     
                    string operande = rules.Substring(positionDeb, positionChaine - positionDeb);
                    if (operande.Length > 0)
                    {
                        // Je recupere ma valeur du dictionnaire pour vérifier sa saisi
                        resultat = groupValids[positionDico];
                        positionDico++;
                        positionChaine++;
                        // Je refais l'appel en incrementant la position dans la chaine et la position dans le dico
                        resultat = checkRule(rules, groupValids, ref positionChaine, positionDico);
                    }
                }
     
                // Il faut que je traite le & et le | ainsi que la parenthèse fermante
                if (rules[positionChaine] == '&')
                {
                    positionChaine++;
                    resultat &= checkRule(rules, groupValids, ref positionChaine, positionDico);
                }
     
                if (rules[positionChaine] == '|')
                {
                    positionChaine++;
                    resultat |= checkRule(rules, groupValids, ref positionChaine, positionDico);
                }
     
                //Tant que l'on est pas à la fin on continue d'avancer
                if (rules[positionChaine] == ')' && positionChaine < rules.Length)
                {
                    positionChaine++;
                    resultat &= checkRule(rules, groupValids, ref positionChaine, positionDico);
                }
     
     
                return resultat;
            }
    Je pense me rapprocher le plus de ce que tu me dis. Ce qui est bien, est que je comprend déjà mieux le code et comment ça fonctionne.
    Il me reste encore des cas à gérer, comme la comparaison avec une autre parenthèse.

    Qu'en penses tu ?

  13. #33
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Oui, tu touches le bon bout, félicitations.
    Voici mes remarques et suggestions.


    * Les bogues:
    a) Tu n'utilises pas la valeur de "operande" dans le cas où l'opérande gauche est un nombre. A la place tu utilises "positionDico" dont je ne vois pas à quoi elle sert.
    b) Tu ne testes pas toujours que index est une position valide. Tu l'as fait seulement à la fin (parenthèses fermantes) et incorrectement (le test de position doit être fait avant le test du caractère).



    * Tu dois définir comment ton algorithme est supposé se comporter avec les chaînes incorrectes. Doit-il être tolérant ou au contraire lever une exception à la moindre erreur ? Est-ce le cas actuellement ? Tes tests couvrent-ils ces cas ?



    * La boucle de recherche du dernier nombre est vraiment sale, tu peux l'améliorer et la raccourcir. Voici quelques conseils en général pour améliorer la lisibilité d'un code. Libre à toi de picorer ce que tu veux.

    a) Éviter les abréviations : "positionDeb" n'est pas explicite pour un développeur qui découvre ta fonction sans connaître le problème. Ca ne vaut pas l'économie de deux caractères (par contre "position" suffirait peut-être à remplacer "positionChaine" vu le contexte). Si tu veux être concis mieux vaut "début".

    b) Déclarer les variables d'une fonction au dernier moment : "chiffre" peut être déclaré dans la boucle.

    c) Utiliser des sous-fonctions. D'abord cela hiérarchise les niveaux de lecture et de compréhension (niveau le plus haut : l'algorithme "si parenthèse parser sous-expression sinon parser nombre", niveau le plus bas les détails "incrémenter telle variable, lire telle variable, etc"). Ensuite des noms bien choisis auto-documentent le code et remplacent avantageusement les commentaires. Parmi les pistes possibles ici : EstUnChiffre, CompterChiffres, TrouverFinDuNombre, LireNombre, etc.

    d) Savoir quand utiliser les "clauses défensives" : ce sont des branchements conditionnels du type "si telle condition alors quitter", ou quitter peut soit être un "return" pour quitter la fonction ou un "break" pour quitter une boucle. Les clauses défensives sont utilisées pour gérer les cas exceptionnels, les conditions aux bords ou, souvent pour les boucles, les conditions de fin. Tu en as justement utilisé une pour le cas où "rules" est vide et ça peut être une piste pour transformer la boucle de recherche de fin du nombre.


    PS : Robert Martin explique très bien tout ça dans "Coder Proprement", un excellent ouvrage que j'aurais aimé lire dix ans plus tôt que je ne l'ai lu (ça m'aurait évité de passer dix ans à à découvrir tout ça par moi-même dans la douleur).

  14. #34
    Membre du Club
    Inscrit en
    Décembre 2005
    Messages
    172
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 172
    Points : 43
    Points
    43
    Par défaut
    Voici mon code nettoyer :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    protected bool checkRule(string rules, Dictionary<int?, bool> groupValids,ref int position)
            {
                int len = rules.Length;
                bool resultat = false;
                if (string.IsNullOrEmpty(rules))
                    return true;
     
                if (position < rules.Length)
                {
                    if (rules[position] == '(')
                    {
                        // Je refais l'appel en incrementant la position dans la chaine
                        position++;
                        resultat = checkRule(rules, groupValids, ref position);
                    }
                    else
                    {
                        // On recupere le nombre qu'il soit sur 1 ou 2 caractères
                        string operande = LireNombre(rules, ref position);
     
                        // On vérifie que l'on a recupéré un nombre
                        if (operande.Length > 0)
                        {
                            // Je recupere ma valeur du dictionnaire pour vérifier sa saisi
                            resultat = groupValids[int.Parse(operande)];
     
                            // Je refais l'appel en incrementant la position dans la chaine
                            position++;
                            resultat = checkRule(rules, groupValids, ref position);
                        }
                    }
     
                    // Il faut que je traite le & et le | ainsi que la parenthèse fermante
                    if (rules[position] == '&')
                    {
                        position++;
                        resultat &= checkRule(rules, groupValids, ref position);
                    }
     
                    if (rules[position] == '|')
                    {
                        position++;
                        resultat |= checkRule(rules, groupValids, ref position);
                    }
     
                    //Tant que l'on est pas à la fin on continue d'avancer
                    if (rules[position] == ')')
                    {
                        position++;
                        resultat &= checkRule(rules, groupValids, ref position);
                    }
                }
     
                return resultat;
            }
    Cependant, lorsque je teste je plante car je sors des limites du tableau (rules). Avec la recursivité, je m'y perds dans le debug mais j'essai de m'accrocher pour trouver le problème.

    De plus, si je tombe en erreur dans ma rules alors je renvoi false et non lever une exception.

    Pour finir, comment je n'arrive pas à comprendre comment garder mon résultat pour le comparer au suivant.
    Je m'explique si j'ai cette règle (1&2)|(3&4) et que j'ai tout saisi alors
    résultat devrait être égale à :
    - True lors de la 1ere operande
    - True & True lors de la 2eme operande qui donnera True
    - ensuite j'arrive au | et la je pèche car je dois garder resultat à True de mon ancien passage et je dois ensuite comparer 3&4 pour pouvoir le vérifier avec le |.

    A Revoir car je ne suis pas

  15. #35
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Concernant test de position, tu vérifies au début mais entretemps tu as modifié cette position et elle peut donc être à nouveau hors-tableau. Tu dois donc ajouter davantage de vérifications, soit après chaque incrémentation (ou après chaque incrémentation possible), soit avant chaque lecture de caractère. Par ailleurs tu t'y es pris d'une façon assez laide dans ton dernier code, mieux vaudrait des clauses défensives (si position invalide alors renvoyer résultat) ou un ET conditionnel (si position valide && caractère == '(' alors).


    Concernant l'ordre d'évaluation, c'est toujours au fil de l'eau:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    (
       True
       &
          True
       )
    |
       (
          True
          &
             True
          )
    Les niveaux représentent la profondeur de la pile d'appel :
    - On est descendu après chaque parenthèse ouverte
    - On est descendu après chaque opérateur booléen (l'opérande droite est toujours une sous-expression)



    PS : Ce n'est qu'un conseil d'ordre général mais sur le long terme tu devrais chercher à avoir moins de commentaires et plus de sous-fonctions dont les noms font office de commentaire.

    PPS : Attention il est possible avec ton code d'avoir des parenthèses ouvertes mais jamais fermées ou, réciproquement, des parenthèses fermées sans parenthèses ouvertes au préalable. Si c'est voulu, très bien.

  16. #36
    Membre du Club
    Inscrit en
    Décembre 2005
    Messages
    172
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 172
    Points : 43
    Points
    43
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    protected bool checkRule(string rules, Dictionary<int?, bool> groupValids,ref int position)
            {
                int len = rules.Length;
                bool resultat = false;
                if (string.IsNullOrEmpty(rules))
                    return true;
     
                if (PositionValide(rules,position))
                {
                    if (PositionValide(rules,position) && rules[position] == '(')
                    {
                        position++;
                        resultat = checkRule(rules, groupValids, ref position);
                    }
                    else
                    {
                        string operande = LireNombre(rules, ref position);
     
                        if (operande.Length > 0)
                        {
                            resultat = groupValids[int.Parse(operande)];
     
                            position++;
                            resultat = checkRule(rules, groupValids, ref position);
                        }
                    }
     
                    if (PositionValide(rules,position) && rules[position] == '&')
                    {
                        position++;
                        resultat &= checkRule(rules, groupValids, ref position);
                    }
     
                    if (PositionValide(rules,position) && rules[position] == '|')
                    {
                        position++;
                        resultat |= checkRule(rules, groupValids, ref position);
                    }
     
                    if (PositionValide(rules,position) && rules[position] == ')')
                    {
                        position++;
                        resultat &= checkRule(rules, groupValids, ref position);
                    }
                }
     
                return resultat;
            }
     
            /// <summary>
            /// Lecture de la règle pour récupérer le prochain nombre qu'il soit sur 1 ou 2 caractères
            /// </summary>
            /// <param name="rules"></param>
            /// <param name="position"></param>
            /// <returns></returns>
            protected string LireNombre(string rules, ref int position)
            {
                int debut = position;
                while (position < rules.Length)
                {
                    if (EstUnChiffre(rules[position].ToString()))
                        position++;
                    else
                        break;
                }
     
                return rules.Substring(debut, position - debut);
            }
     
            /// <summary>
            /// Vérifie que le champ valeur est un entier
            /// </summary>
            /// <param name="valeur"></param>
            /// <returns></returns>
            protected bool EstUnChiffre(string valeur)
            {
                int chiffre;
                return int.TryParse(valeur, out chiffre);
            }
     
     
            /// <summary>
            /// Vérifie que la position est inférieur à la taille de la règle
            /// </summary>
            /// <param name="valeur"></param>
            /// <returns></returns>
            protected bool PositionValide(string rules, int position)
            {
                return (position < rules.Length? true: false);
            }
    Je fais mon test de position dans tous les cas et tu avais raison à ce sujet. Normal que je soit en erreur.

    PPS : Attention il est possible avec ton code d'avoir des parenthèses ouvertes mais jamais fermées ou, réciproquement, des parenthèses fermées sans parenthèses ouvertes au préalable. Si c'est voulu, très bien.
    Je devrais avoir le même nombre de parenthèses ouvertes que de fermées. C'est une obligation.


    Mon script ne fonctionne pas comme voulu car il renvoit false quand j'ai ceci (True&True)|(false&false) ==> je devrais avoir true

  17. #37
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Il y a au moins un bogue dans ta gestion des nombres : tu incrémentes à nouveau position alors que LireNombre devrait déjà t'avoir positionné correctement. Pour le reste il faut y aller au débogage pas à pas.

    Je devrais avoir le même nombre de parenthèses ouvertes que de fermées. C'est une obligation.
    Oui mais une erreur est vite arrivée, d'où l'intérêt d'avoir des vérifications qui te sautent au visage plutôt que des erreurs silencieuses et difficiles à trouver. Dans le même genre si j'étais toi j'ajouterais une condition pour vérifier que le premier appel se termine bien à la fin de la chaîne pour s'assurer que tout a été parsé.

  18. #38
    Membre du Club
    Inscrit en
    Décembre 2005
    Messages
    172
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 172
    Points : 43
    Points
    43
    Par défaut
    J'ai modifié mon code et retirer le position++ à cette endroit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    if (operande.Length > 0)
                        {
                            resultat = groupValids[int.Parse(operande)];
     
                            //position++;
                            resultat = checkRule(rules, groupValids, ref position);
                        }
    Franchement je n'arrive pas à trouver où est le problème.
    J'ai toujours False dans tous les cas.

    Dans le même genre si j'étais toi j'ajouterais une condition pour vérifier que le premier appel se termine bien à la fin de la chaîne pour s'assurer que tout a été parsé.
    Tu veux dire quoi par là ? Je ne suis pas car je fais déjà mon test sur la position < rules.length.

  19. #39
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Citation Envoyé par Naruto_kun Voir le message
    J'ai modifié mon code et retirer le position++ à cette endroit:
    Au passage tu pourrais aussi virer la vérification de la longueur de l'opérande: de toute façon elle doit être supérieure à zéro. Si ce n'était pas le cas cela voudrait dire qu'il y a une erreur quelque part, donc autant avoir cette erreur le plus tôt possible (pllus une erreur est détectée tôt, plus le problème est facile à déboguer).

    Franchement je n'arrive pas à trouver où est le problème.
    J'ai toujours False dans tous les cas.
    Tel quel je ne vois aucun problème. Prends le débogueur et avance pas-à-pas (F10/F11) pour savoir à quel moment l'erreur apparaît. C'est l'occasion d'acquérir ou de perfectionner des compétences qui te seront extrêmement utiles et vont te faire gagner du temps.

    Tu veux dire quoi par là ? Je ne suis pas car je fais déjà mon test sur la position < rules.length.
    Ce que je veux dire c'est qu'une fois que le parsing est terminé, position devrait être égal à rules.Length. Vérifier cela peut être une bonne idée, à nouveau pour réduire le risque d'erreur silencieuse.

  20. #40
    Membre du Club
    Inscrit en
    Décembre 2005
    Messages
    172
    Détails du profil
    Informations forums :
    Inscription : Décembre 2005
    Messages : 172
    Points : 43
    Points
    43
    Par défaut
    Mon script n'est pas bon. Je suis d'accord avec toi qu'il parse ma rues mais le probleme est que si je rencontre cette rules (1&2)|(3&4).
    Je devrais récupérer false alors qu'il me renvoi car il fait
    (True&True)|(True&True) ==> TRUE

    Aurais tu une idée de comment tourner mon algo pour qu'il vérifie cela?
    Merci

Discussions similaires

  1. mise en place macros complexes
    Par magalie0210 dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 24/01/2012, 20h00
  2. [AD]Mise en place de Active Directory
    Par guiguisi dans le forum Windows Serveur
    Réponses: 9
    Dernier message: 29/07/2004, 08h50
  3. [C#] Mise en place d'un site multilingue
    Par regbegpower dans le forum ASP.NET
    Réponses: 6
    Dernier message: 19/03/2004, 19h15
  4. mise en place serveur web intranet
    Par gui4593 dans le forum Installation
    Réponses: 7
    Dernier message: 01/01/2004, 18h18
  5. Mise en place d'index....??
    Par liv dans le forum Requêtes
    Réponses: 6
    Dernier message: 18/12/2003, 11h04

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo