Evaluation d'une expression booléenne contenue dans une string [Résolu]

arthur24 17 Messages postés mardi 16 décembre 2003Date d'inscription 20 août 2015 Dernière intervention - 7 déc. 2007 à 09:55 - Dernière réponse : divadav 97 Messages postés lundi 13 janvier 2003Date d'inscription 22 janvier 2009 Dernière intervention
- 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.
Afficher la suite 

11 réponses

Répondre au sujet
Renfield 17307 Messages postés mercredi 2 janvier 2002Date d'inscription 18 janvier 2017 Dernière intervention - 7 déc. 2007 à 10:47
+3
Utile
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
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Renfield
arthur24 17 Messages postés mardi 16 décembre 2003Date d'inscription 20 août 2015 Dernière intervention - 18 déc. 2007 à 10:08
+3
Utile
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.
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de arthur24
pneau 258 Messages postés mercredi 21 avril 2004Date d'inscription 27 octobre 2010 Dernière intervention - 7 déc. 2007 à 10:11
0
Utile
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
Commenter la réponse de pneau
pneau 258 Messages postés mercredi 21 avril 2004Date d'inscription 27 octobre 2010 Dernière intervention - 7 déc. 2007 à 10:15
Commenter la réponse de pneau
arthur24 17 Messages postés mardi 16 décembre 2003Date d'inscription 20 août 2015 Dernière intervention - 7 déc. 2007 à 10:25
0
Utile
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

@+
Commenter la réponse de arthur24
arthur24 17 Messages postés mardi 16 décembre 2003Date d'inscription 20 août 2015 Dernière intervention - 7 déc. 2007 à 11:06
0
Utile
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+
Commenter la réponse de arthur24
Renfield 17307 Messages postés mercredi 2 janvier 2002Date d'inscription 18 janvier 2017 Dernière intervention - 7 déc. 2007 à 15:10
0
Utile
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
Commenter la réponse de Renfield
arthur24 17 Messages postés mardi 16 décembre 2003Date d'inscription 20 août 2015 Dernière intervention - 17 déc. 2007 à 16:54
0
Utile
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+
Commenter la réponse de arthur24
Renfield 17307 Messages postés mercredi 2 janvier 2002Date d'inscription 18 janvier 2017 Dernière intervention - 17 déc. 2007 à 19:39
0
Utile
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
Commenter la réponse de Renfield
divadav 97 Messages postés lundi 13 janvier 2003Date d'inscription 22 janvier 2009 Dernière intervention - 20 déc. 2007 à 15:23
0
Utile
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
Commenter la réponse de divadav
divadav 97 Messages postés lundi 13 janvier 2003Date d'inscription 22 janvier 2009 Dernière intervention - 20 déc. 2007 à 18:51
0
Utile
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
Commenter la réponse de divadav

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.