Evaluation d'une expression booléenne contenue dans une string

Résolu
arthur24 Messages postés 17 Date d'inscription mardi 16 décembre 2003 Statut Membre Dernière intervention 20 août 2015 - 7 déc. 2007 à 09:55
divadav Messages postés 94 Date d'inscription lundi 13 janvier 2003 Statut Membre Dernière intervention 22 janvier 2009 - 20 déc. 2007 à 18:51
Bonjour à tous,

Voici mon problème. Je travaile sous VS2005 et je tente d'évaluer une
condition booléenne contenue dans une variable de type string.

La variable est simplement déclarée par : dim str as string
A l'issu d'un traitement, le contenu de la variable est du type
"((<valeur_booléenne>)AND(<valeur_booléenne>))" et je cherche à évaluer cette
expression pour obtenir la valeur booléenne de l'ensemble de l'expression.

J'ai pensé résoudre le problème par l'appel de Cbool : cBool(str) mais
j'obtiens le message "La conversion de la chaîne "((True)AND(True))" en type
'Boolean' n'est pas valide."

La fonction Cbool n'accepte pas en paramètre de variable de type string.
L'anomalie est la même  avec l'appel directe sous la forme
cbool("((True)AND(True))"). Par contre, l'exécution de cbool((True)AND(True))
retourne bien la valeur True.

La fonction Cbool n'est visiblement pas le bon moyen pour évaluer une chaîne
de caractère contenant une expression booléenne. Mais je ne connais pas
d'autre moyen de résoudre ce problème.

Merci par avance de votre aide.

11 réponses

Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
7 déc. 2007 à 10:47
je joues beaucoup avec ce genre de choses, ces temps-ci...

joues avec ton parenthesage, justement...
remplace les variables par 1 ou 0

et traite ce qui se trouve entre parentheses...

((((a) and (b)) or (c)) and (d))
((( 1  and  0 ) or   1 ) and  1 )
((         0       or   1 ) and  1 )
(         1   and  1 )
          1

si tu structures bien la chose, ca devrait etre maintenable et pas trop long

tu parcoures ta chaine, tu mémorise la pos de ta parenthese ouvrante
si tu tombes sur une autre ( , tu stocke sa position (tu ecrase l'autre)
si tu tombes sur ), tu traites (récursif) l'expression contenue entre les deux parentheses et tu modifie la chaine d'entrée...

ca va te simplifier la chose et tu tombera rapidement sur ton résultat.

Renfield
Admin CodeS-SourceS- MVP Visual Basic
3
arthur24 Messages postés 17 Date d'inscription mardi 16 décembre 2003 Statut Membre Dernière intervention 20 août 2015
18 déc. 2007 à 10:08
Depuis quelques jours je me disais que des outils externes au code (SQL, Excel,...) devait bien permettre d'évaluer des expressions booléennes. Connaissant mieux SQL, j'ai fait quelques recherches sur le sujet et, ce matin, je suis tombé sur cet article :

http://www.sqlservercentral.com/articles/Advanced+Querying/evaluatingbooleanexpressionsusingtsql/1631/

J'ai trouvé dans la procédure stockée décrite les éléments qui me manquaient pour formater correctement une expression analysable, par exemple, par SQL Server.

Le "AND" devient &, le "OR" devient |, etc.
Le "TRUE" devient 1, le "FALSE" devient 0.

Il suffit de reformater l'expression booléenne de départ pour l'exprimer avec les opérateur du SGBD, constituer une requète du style "SELECT " & MonExpressionBool et d'exécuter le tout comme n'importe quelle requète.

Le SGBD retourne le résultat de l'évaluation, sans soucis de profondeur dans le parenthésage, et quelle qu'en soit la structure.

Bien sur, cette solution n'est pas élégante du point de vue algorithmique. Elle déplaira aux fans de la récursion, mais elle a le mérite d'être simple et immédiatement applicable dans une application adossée à une base de données.

Ces quelques jours auront eu le mérite de me replonger dans les joies des fonctions réccursives, ça faisait longtemps...

Merci à tous de votre aide.
3
pneau Messages postés 258 Date d'inscription mercredi 21 avril 2004 Statut Membre Dernière intervention 27 octobre 2010 5
7 déc. 2007 à 10:11
salut,
est ce que ta chaine contient systématique 2 booléens ? et le mot clé And ?
le mieux, à mon avis est de faire une recherche grace aux parenthèses.
en parcourant la chaine de manière séquentiel tu pourras détecter les valeurs des booléens et l'opérateur

sinon, tu peux essayer en faisant des recherches des valeurs "TRUE" et "FALSE" avec instr 
      
@+

Pat

 Don't Worry , Be Happy

<hr />lorsque le problème est résolu, pensez Réponse Acceptée
0
pneau Messages postés 258 Date d'inscription mercredi 21 avril 2004 Statut Membre Dernière intervention 27 octobre 2010 5
7 déc. 2007 à 10:15
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
arthur24 Messages postés 17 Date d'inscription mardi 16 décembre 2003 Statut Membre Dernière intervention 20 août 2015
7 déc. 2007 à 10:25
L'expression citée est un exemple simplifié.

Elle est du type : [ ( ]  [(<valeur_booléenne>)] [And,Or]  [ (<valeur_booléenne>) ]  [ ) ] ce qui peut donner par exemple :
((((true) and (false)) or (true)) and (false)).

Le parenthésage est toujours complet, sans omission basée sur la priorité des opérateurs logique.

Mon problème n'est pas de détecter les valeurs booléennes mais d'évaluer l'expression complète pour obtenir une valeur booléenne.

Je cherche donc une fonction dont la déclaration pourrait ressembler à :

Function ExvalueExpressionBooleenne(ByVal Expression As String) As Boolean

@+
0
arthur24 Messages postés 17 Date d'inscription mardi 16 décembre 2003 Statut Membre Dernière intervention 20 août 2015
7 déc. 2007 à 11:06
C'est bien ce que je craignais, il va falloir que je code un parseur d'expressions booléennes.

J'espérais trouver un bout de code qui ferait le boulot, histoire de ne pas réinventer la roue...

Mais quand il faut y aller !!! Du coup, lorsqu'il sera au point je le posterai

A+
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
7 déc. 2007 à 15:10
c'est pas très complexe, tu as l'avantage d'avoir les parentheses bien placées....
l'histoire de 45 minutes de coding, pour avoir un truc fonctionnel...

Renfield
Admin CodeS-SourceS- MVP Visual Basic
0
arthur24 Messages postés 17 Date d'inscription mardi 16 décembre 2003 Statut Membre Dernière intervention 20 août 2015
17 déc. 2007 à 16:54
Chose promise, chose due, voici une fonction qui évalue les expressions booléennes au format suivant :  [ ( ]  [(<valeur_booléenne>)] [And,Or]  [
(<valeur_booléenne>) ]  [ ) ] ce qui peut donner par exemple : ((((1) and (0)) or (1)) and (0)).

Au cours des tests, je suis tombé sur un cas particulier que je ne traite pas encore correctement, mais que je ne devrais pas rencontrer dans l'appli sur laquelle je travaille  : une expression du type ((1)AND((0)or(1))), càd une expression dont le niveau de parenthésage le plus profond n'est pas le premier exprimé. Dans ce type de cas, ma fonction se plante. Je pense qu'il faudrait non plus parser en recherchant les parenthèses mais plutôt les opérateurs logiques.

N'hésitez pas à me faire part de vos remarques.

    Public Function ParseBoolExp(ByVal ExpressionBool As String) As Boolean
        Dim posO, posF, i As Integer
        Dim FinTrt As Boolean
        'Longueur d'un élément booléen, 3 pour (0) ou (1) et 6 pour (true) ou (fals)
        Const LenElemBool = 3

        FinTrt = False
        i = 0
        While ExpressionBool(i) = "("
            i = i + 1
        End While
        posO = i
        posF = InStr(Mid(ExpressionBool, posO + LenElemBool), ")") + posO + 2
        Select Case Mid(ExpressionBool, posO, posF - posO + 1).ToUpper
            Case "(1)AND(1)", "(0)AND(0)", "(1)OR(1)", "(0)OR(1)", "(1)OR(0)"
                ExpressionBool = Left(ExpressionBool, posO - 1) & "1" & Mid(ExpressionBool, posF + 1)
                If ExpressionBool = "1" Then
                    FinTrt = True
                    ParseBoolExp = True
                End If
            Case "(0)AND(1)", "(1)AND(0)", "(0)OR(0)"
                ExpressionBool = Left(ExpressionBool, posO - 1) & "0" & Mid(ExpressionBool, posF + 1)
                If ExpressionBool = "0" Then
                    FinTrt = True
                    ParseBoolExp = False
                End If
            Case "1", "(1)"
                ParseBoolExp = True
                FinTrt = True
            Case "0", "(0)"
                ParseBoolExp = False
                FinTrt = True
        End Select
        If Not (FinTrt) Then
            ParseBoolExp = ParseBoolExp(ExpressionBool)
        End If

A+
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
17 déc. 2007 à 19:39
pas mal...
reste a supprimer les parenthèses qui entourent toute la chaine ; ton cas non prévu.

vu que tu t'amuses a gérer toutes les combinaisons, suffirait de faire des Replace...

remplacer (0)And(1) par (0) etc
0
divadav Messages postés 94 Date d'inscription lundi 13 janvier 2003 Statut Membre Dernière intervention 22 janvier 2009 2
20 déc. 2007 à 15:23
Salut Salut !

Je vois que tu as déjà accepté des réponses, et que tu n'as donc (normalement) plus de problème... Permet moi cependant d'ajouter une petite contribution !

En fait, il existe un moyen en .Net d'évaluer une expression de type chaîne comme du code VB ou C#.

Pour cela, il faut utiliser des objets comme VBCodeProvider, et les méthodes de System.Reflexion.

Si je reprend ta problématique, tu dis entre autre vouloir une fonction avec le prototype suivant :
Function ExvalueExpressionBooleenne(ByVal Expression As String) As Boolean

Et bien voici à quoi cela ressemblerait :

<hr size="2" width="100%" />Function ExvalueExpressionBooleenne(ByVal Expression As String) As Boolean

    Dim vbCode As VBCodeProvider = New VBCodeProvider

    Dim cParam As CompilerParameters = New CompilerParameters

    ' Ajout des références

    cParam.ReferencedAssemblies.Add("system.dll")

    ' Options du compilateur

    cParam.CompilerOptions = "/t:library"

    cParam.GenerateInMemory = True

    ' Génération du code source

    Dim sCode As StringBuilder = New StringBuilder("")

    sCode.AppendLine("Imports System")

    sCode.AppendLine("Namespace Divad")

    sCode.AppendLine(vbTab & "Class EvalVbCode")

    sCode.AppendLine(vbTab & vbTab & "Public Function EvalBooleanExpression(ByVal expr As String) As Boolean")

    sCode.AppendLine(vbTab & vbTab & vbTab & "Try")

    sCode.AppendLine(vbTab & vbTab & vbTab & vbTab & "Return " & expr)

    sCode.AppendLine(vbTab & vbTab & vbTab & "Catch ex As Exception")

    ' En cas d'erreur : console de debug

    sCode.AppendLine(vbTab & vbTab & vbTab & vbTab & "Debug.WriteLine(ex.Message)")

    sCode.AppendLine(vbTab & vbTab & vbTab & vbTab & "Return Nothing")

    sCode.AppendLine(vbTab & vbTab & vbTab & "End Try")

    sCode.AppendLine(vbTab & vbTab & "End Function")

    sCode.AppendLine(vbTab & "End Class")

    sCode.AppendLine("End Namespace")

    ' Code de la classe dans la console de debug

    Debug.WriteLine(sCode.ToString())

    Dim cResult As CompilerResults = vbCode.CompileAssemblyFromSource(cParam, sCode.ToString())

    Dim myAssembly As System.Reflection.Assembly = cResult.CompiledAssembly

    Dim oEvalVbCode As Object = myAssembly.CreateInstance("Divad.EvalVbCode")

    Dim tEvalVbCode As Type = oEvalVbCode.GetType()

    Dim methodEvalBool As MethodInfo = tEvalVbCode.GetMethod("EvalBooleanExpression")

    Dim myBoolean As Boolean = methodEvalBool.Invoke(oEvalVbCode, New Object() {Expression})

    Return myBoolean

   

End Function

<hr size="2" width="100%" />En fait, j'ai justement posté un article hier là-dessus : http://www.laumaille.net/2007/12/19/evaluationexecution-dune-chaine/

J'espère avoir pu t'aider !!

<hr size="2" width="100%" />Divad
Techniques de Web Design, Traductions d'articles sur le Web Design, et Astuces .Net
0
divadav Messages postés 94 Date d'inscription lundi 13 janvier 2003 Statut Membre Dernière intervention 22 janvier 2009 2
20 déc. 2007 à 18:51
Oups, je me rends compte que j'ai oublié une ligne dans l'exemple que je donne... Il fallait lire :
<hr size="2" width="100%" />    ' Génération du code source
    Dim sCode As StringBuilder = New StringBuilder("")
    sCode.AppendLine("Imports System")
sCode.AppendLine("Imports System.Diagnostics")
    sCode.AppendLine("Namespace Divad")

<hr size="2" width="100%" />Hé oui, si on n'importe pas "System.Diagnostics", ça fait une erreur à la compilation : il ne voit pas l'objet "Debug", et ne peut donc pas compiler...

P.S. : Au fait, on fait comment pour modifier un message et éviter le double post ?

<hr size="2" width="100%" />Divad
Techniques de Web Design, Traductions d'articles sur le Web Design, Astuces .Net
0
Rejoignez-nous