pourriez vous m'indiquer comment orienter mon algo?
Je sens que l'on approche du bout.
Merci
Version imprimable
pourriez vous m'indiquer comment orienter mon algo?
Je sens que l'on approche du bout.
Merci
Tu as maintenant un algo qui vérifie tes règles. Le problème c'est que tu as découvert que tes règles ne conviennent pas. Donc soit tu réécris tes règles, soit tu décides que "&" ne veut pas dire "&", que "|" ne veut pas dire "|" etcétéra.
Dans ce dernier cas tu dois formaliser ce dont tu as besoin, c'est à dire expliquer le nouveau comportement général que tu désires, avec une règle applicable à tous les cas et pas seulement un exemple. Tu es le seul à savoir toute la diversité de cas que tu pourrais rencontrer et ce que tu veux obtenir. Que se passe t-il par exemple quand il y a six valeurs ? Sept valeurs ? Douze valeurs avec plusieurs niveaux ?
Je ne peux pas répondre avant que tu aies formalisé. Mais si ça se trouve tout est à jeter et dès le départ des équations booléennes n'étaient pas adaptées à ton problème.Citation:
Du coup, ai je un gros changement à faire dans mon code ?
Par contre cette fois essaie de cerner correctement le problème dès le début, histoire de ne pas reperdre deux semaines sur une solution qui n'a aucun intérêt parce que pas adaptée au problème.
Un expression doit commencer par une parenthèse ouverte ou un nombre. Donc dans le second cas tu ne devrais jamais avoir une chaîne "opérande" vide. En choisissant de tester ce cas afin de ne pas lever d'exception tu te retrouves à supporter un cas invalide, pour lequel tu renvoies un résultat erroné. Mieux vaudrait laisser le programme planter pour te permettre de détecter l'erreur.
a) Ne cherche jamais à gérer les cas invalides qui ne devraient jamais se produire (sauf en cas d'erreur de ta part).
b) Fais en sorte que ces cas invalides plantent bruyamment et dès que possible.
merci pour ton explication.
Je vais te formaliser exactement et précisément ce que je souhaite:
Partons du fait que mes parenthèses représentent des niveaux.
Si j'ai (a&b) alors je n'ai qu'un niveau :
(a&b)
(
|
-- a
|
-- ET(&)
|
-- b
|
)
Cela signifie que que je devrais renseigner a et b pour valider ma règle.
Autre Exemple avec ((a&b)|(c&d)) :
((a&b)|(c&d))
(
|
|
-- (
| |
| -- a
| |
| -- ET(&)
| |
| -- b
| |
| )
|
|
--OU (|)
|
|
-- (
| |
| -- c
| |
| -- ET(&)
| |
| -- d
| |
| )
|
|
)
je devrais avoir:
-soit a et b renseigné mais ni c ni d
OU
-soit c et d renseigné mais ni a ni b
Il faut voir les priorités dans la règle comme des les règles mathématique au niveau des parenthèses, mais il faut tout de même analyser le reste de l'expression pour vérifier toute la règle.
Dans un premiers temps, on regroupe par parenthèse et on analyse pour renvoyé soit true soit false.
Plus j'ai des paramètres, plus ma règle sera longue si besoin.
Ce n'est pas simple à comprendre mais sur les derniers commentaire on a sorti exactement mon besoin avec DonQuiche et StringBuilder.
Le | faut le comprendre comme un ^ou exclusif bien evidement. Je changerais ma syntaxe à l'avenir dans ma règle mais pour le moment je vais fonctionner comme cela.
Si tu souhaites d'autres précisions je suis à ta disposition.
Merci
Tu m'as malheureusement mal compris.
J'avais bien saisi que tu voulais que "(a et b) ou (c et d)" soit en fait compris comme "(a et b mais ni c ni d) OU (c et d mais ni a ni b)". Mais ça c'est un exemple particulier. Qu'en est-il pour les autres formules ? Comment faut-il les interpréter ?
Peux-tu par exemple avoir une règle "((a&b)&(c&d))|((e|f)&(g^h))" ? Comment veux-tu l'interpréter alors ?
PS : J'ai l'impression que tu restes sur l'idée que c'est un bogue de l'algo qui ne considérerait pas la formule dans son ensemble. Si oui oublie tout de suite cette idée : l'algo fonctionne correctement, c'est toi qui exiges un comportement qui ne correspond pas aux règles mathématiques que tu donnes.
Il faut pouvoir interpréter toutes les formules.
Par contre, je n'aurais pas de ^. J'aurais comme opérande uniquement & et | qu'il faut interpréter comme un ET et un OU exclusif.
Je peux avoir toute sorte de formule.
Par exemple celle que tu fournit : ((a&b)&(c&d))|((e|f)&(g^h))" serait ecrite comme cela ((a&b)&(c&d))|((e|f)&(g|h)).
A la place du ^j'aurais |.
Ca me donnerait :
- soit a et b et c et d mais ni e,f,g,h
- soit e et g ni f ,h ,a, b, c, d
- soit e et h ni f ,g ,a , b, c, d
- soit f et g ni e ,h ,a , b, c, d
- soit f et h ni e ,g ,a , b, c, d
interpréter les opérandes et les parenthèses en fonction de leur position.
En somme un ensemble d'opérandes est accepté si :
a) La règle est vraie.
b) Si une opérande vraie quelconque passe à faux, alors la règle est fausse.
Dans ce cas c'est facile, tu testes d'abord la première condition avec l'algo obtenu jusqu'ici puis pour chaque opérande vraie tu vérifies qu'en la passant à faux la règle devient fausse, toujours avec l'algo établi jusqu'ici. Ca fonctionnera tant que tu n'auras pas d'opérateur négation (NON) et qu'un résultat faux n'aura pas de conditions additionnelles.
Mais ton problème sent vraiment le poisson. A mon avis il est mal posé ou c'est une idée tordue pour l'UI. A mon avis tes règles n'ont pas besoin d'être quelconques, tu n'as jamais eu besoin d'algèbre booléenne mais seulement de tester quelques combinaisons précises. Si oui tu aurais mieux faut d'exprimer tes règles ainsi (pour reprendre le dernier exemple) en énumérant simplement les ensembles valides :
(a,b,c,d) ; (e,g) ; (f,h) ; (f,g)
Ça aurait été un jeu d'enfant à parser et ça aurait été beaucoup plus simple à comprendre.
je suis d'accord avec toi sur ce que tu dis à la fin.
Je m'adapte au projet. Je fais de la maintenance et je ne peux pas tout modifier comme cela.
Je prend conscience de ce que je demande et j'avoue que je m'exprime mal mais c'est pas simple non plus à comprendre.
Toutes mes valeurs dépendent de ma formule.
Ma formule est écrite de la sorte car si je suis en erreur alors je l'affiche en remplaçant le & par ET et le | par OU. Que ce soit parlant à l'utilisateur finale.
Je m'excuse encore une fois pour toute ça. Je ne peux pas faire autrement.
Bonjour,
Ton algo c'est a but pédagogique ou fonctionnel ?
Personnellement je m'orienterai plutôt (peut-etre a tord)
vers les CodeDom pour faire ta fonction afin d’exécuter a la volée ta requête
(voir code ci-dessous desolé pour les commentaires j'ai fait ca vite)
---------------------------------------------------------------------------
Code:
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 /* * Crée par SharpDevelop. * * \file ...............cs * \author Mister MOK * \version 1.0 * \date 04/02/2014 * \time 19:21 * \brief Classe .............. * * \details .............. */ using System; using System.Collections; using System.CodeDom.Compiler; using System.Reflection; using System.Collections.Generic; namespace TestParser { public class FormuleParser { public bool m_Error; private string strInstrDbl = string.Empty; private string strInstrBool = string.Empty; public object myobj = null; public ArrayList errorMessages; public void PrepareFormule(string expr, int NbVAR) { expr = expr.ToLower(); errorMessages = new ArrayList(); CodeDomProvider cp = CodeDomProvider.CreateProvider("C#"); CompilerParameters cpar = new CompilerParameters(); cpar.GenerateInMemory = true; cpar.GenerateExecutable = false; cpar.ReferencedAssemblies.Add("system.dll"); System.Text.StringBuilder SB = new System.Text.StringBuilder(); //-------------------------------------------------------- SB.Append("using System;"); SB.Append("[Serializable]"); SB.Append("class clsExecCode"); SB.Append("{"); SB.Append("public clsExecCode(){}"); #region fonctions compilée a la voléee strInstrBool = "public bool evalBOOL("; strInstrBool += "bool var1"; for (byte i = 1; i < NbVAR ; i++) strInstrBool += ",bool var" + (i+1).ToString(); strInstrBool += ")"; SB.Append(strInstrBool); SB.Append("{"); SB.Append("try"); SB.Append("{return " + expr + ";}"); SB.Append("catch"); SB.Append("{return false;}"); SB.Append("}"); #endregion SB.Append("}"); //-------------------------------------------------------- CompilerResults cr = cp.CompileAssemblyFromSource(cpar, SB.ToString()); foreach (CompilerError ce in cr.Errors) // ajout des erreurs éventuelles errorMessages.Add(ce.ErrorText); if (cr.Errors.Count == 0 && cr.CompiledAssembly != null) { Type ObjType = cr.CompiledAssembly.GetType("clsExecCode"); try { if (ObjType != null) myobj = Activator.CreateInstance(ObjType); } catch (Exception ex) { errorMessages.Add(ex.Message); } m_Error = true; } else m_Error = false; } public bool eval(bool[] TAB) { bool val = false; Object[] myParams = new object[TAB.Length]; for (byte i = 0; i < TAB.Length; i++) myParams[i] = (Object)TAB[i]; if (myobj != null) { MethodInfo evalMethod = myobj.GetType().GetMethod("evalBOOL"); val = (bool)evalMethod.Invoke(myobj, myParams); } return val; } } //------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------ class Program { public static void Main(string[] args) { Console.WriteLine("Hello World!"); FormuleParser TestFormule = new FormuleParser(); TestFormule.PrepareFormule("(var1 & var2) | (var1 & var3) ",3); bool X = TestFormule.eval(new bool[]{true,true,true}); Console.Write(string.Format("\r\n{0}\r\n\r\n",X)); // TODO: Implement Functionality Here Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } } } }
MisterMok > Merci pour ton aide mais ton algo est un peu trop complexe pour moi. je ne comprend pas tout car malheureusement pas assez expérimenté.
C'est à but fonctionnel que je fait cet algo.
C'est une application que j'ai repris et dont je fais la maintenance.
En tout cas, je te remercie beaucoup pour ton aide. Je suis pas loin du résultat que je souhaite. Il reste encore des cas à gérer.
Le code est moins compliqué qu'il n'y parait. Ca semble lourd mais c'est surtout
parce que c'est long a lire a cause des verifications. Mais au final tu écris dynamiquement ta fonction et l'exploite comme si tu l'avais créée dans ton code
Vas te créer une classe intégrant ta fonction du genre :Code:
1
2
3 FormuleParser TestFormule = new FormuleParser(); TestFormule.PrepareFormule("(var1 & var2) | (var1 & var3) ",3); // 3 parametres
qu'au final tu appelle comme ceci :Code:
1
2
3
4
5 public bool evalBOOL(bool var1, bool var2, bool var3) { return (var1 & var2) | (var1 & var3) ; }
où var1 = true ; var2 = true ; var3 = true;Code:
1
2 bool X = TestFormule.eval(new bool[]{true,true,true});
Après si tu veux créer 8 entrée tu fais :
Mais je comprend , si tu arrives à la fin ce serait dommage d'abandonnerCode:
1
2
3
4 FormuleParser TestFormule = new FormuleParser(); TestFormule.PrepareFormule("Test a faire",8); // 8 parametres bool X = TestFormule.eval(new bool[8]{true,true,true,true,true,true,true,true});
si près du but ( et surtout frustrant )
Bon dev à toi, et courage !
Même si effectivement ça n'a plus d'intérêt au point où il en est, je reconnais que rétrospectivement je lui aurais conseillé CodeDom si j'avais su que le parser lui poserait autant de difficultés. Mes premiers pas sont très loin derrière moi, j'ai déjà écrit plusieurs parsers et je n'avais pas réalisé que c'était conceptuellement aussi difficile à comprendre.
CodeDom a le gros avantage d'être conceptuellement plus simple et pour un débutant c'est essentiel. En revanche la mise en oeuvre est finalement plus complexe et plus lourde que le parser que j'avais proposé en page 1, qui est une magnifique petite chose de 70 lignes aérées et bien découpées, très élégante et légère, et fonctionnelle dans tous les environnements (ce qui n'est pas le cas de CodeDom qui nécessite des privilèges peu recommandés sur un serveur).
Franchement je ne sais plus quoi faire et où faire mes modifs.
Dois je revenir en arrière et tout revoir Ou continuer dans ma démarche et faire des modifs mais je ne sais même pas ou.
Desole pour tout
Dans mon précédent post j'avais formalisé ton problème ainsi :
a) La règle doit être vraie.
b) Si une opérande vraie quelconque passe à faux, alors la règle doit devenir fausse.
L'algo actuel, tel que tu me l'avais récemment présenté, permettait de vérifier si ta règle est vraie ou fausse. Tu peux l'utiliser tel quel. Simplement ça ne suffit pas : quand la règle est vraie, tu dois ensuite vérifier qu'elle devient fausse si n'importe quelle opérande vraie devient fausse.
En somme si tu as une règle f et quatre opérandes a=1, b=1, c=0, d=0 alors tu dois vérifier que :
a) f(1, 1, 0, 0) == 1
b) f(0, 1, 0, 0) == 0
c) f(1, 0, 0, 0) == 0
Ton code actuel te permet d'évaluer f.
Oui ok.
Comment je fais ça dans mon code?
Moi je dois verifier que j'ai vrai au départ et si pour le reste j'ai faux alors je suis ok. Par contre si le reste est vrai ou une opérande est vrai alors en retour je suis faux.
Pas très simple à comprendre.
Quel modif je dois faire dans mon algo et a quel niveau du code?
Merci
Pour chaque opérande, si elle est vraie, alors tu la mets à faux, tu appelles ton algo, tu vérifies le résultat, puis tu la remets à vrai et tu passes à la suivante.
Et tout ça doit être dans une nouvelle fonction de plus haut niveau que ton algo actuel.
Coucou,
je suis de retour apres 2semaines d'absence.
Desole mais ma femme a accouché et j'ai du faire le pompier.
Bref, revenons à nos problèmes.
Ce que tu m'indiques DonQuiche et que je dois fausser mon resultat au fur et à mesure que j'avance dans l'analyse de chaque opérande.
Tu me dis de mettre une fonction de plus haut niveau qui appel mon l'algo que j'ai mis en place, mais là je ne comprends pas car je devrais faire appel à l'algo pour chaque opérande.
Voici mon code d'appel à la fonction
Voici ma fonction checkRuleCode:
1
2
3
4 int position = 0; bool isOK; isOK = checkRule(RuleValidator, ParamSaisie, ref position);
Ce que tu me dis ne fonctionnera pas ou peut etre je me trompe.:?Code:
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 protected bool checkRule(string rules, Dictionary<int?, bool> validGroups,ref int position) { int len = rules.Length; bool resultat =true; if (string.IsNullOrEmpty(rules)) return true; if (PositionValide(rules,position)) { if (PositionValide(rules,position) && rules[position] == '(') { position++; resultat = checkRule(rules, validGroups, ref position); } else { string operande = LireNombre(rules, ref position); if (!string.IsNullOrEmpty(operande)) { resultat = validGroups[int.Parse(operande)]; //position++; resultat = checkRule(rules, validGroups, ref position); } } if (PositionValide(rules,position) && rules[position] == '&') { position++; resultat &= checkRule(rules, validGroups, ref position); } if (PositionValide(rules,position) && rules[position] == '|') { position++; resultat ^= checkRule(rules, validGroups, ref position); } if (PositionValide(rules,position) && rules[position] == ')') { position++; resultat = checkRule(rules, validGroups, ref position); } } return resultat; }
Félications pour cet heureux événement. Par contre tu n'as pas du tout compris ce que j'avais expliqué : il fallait garder ton algo intact et en faire une sous-partie d'une solution plus vaste.
Je renomme ton ancien algo checkRules en "parseExpression". Version précédente, inchangée. Voici le nouveau checkRules:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 checkRules(...) si !parseExpresion(...) retourner faux pour chaque opérande si isOperandOptional(...) retourner faux fin retourner vrai fin isOperandOptional(...) si opérande == faux retourner faux opérande = faux var résultat = parseExpression(...) opérande = vrai retourner résultat // toujours vrai malgré le changement de valeur pour cette opérande? fin