Evaluation récursive d'une expression sous forme de chaîne

Soyez le premier à donner votre avis sur cette source.

Vue 3 304 fois - Téléchargée 381 fois

Description

Calcul d'une expression sous forme de texte.
Je vous présente la fonction a_EvalString permettant de calculer des expressions de la plus simple à la plus compliquée. contenant les fonctions mathématiques de base. La fonction est prévue pour traîter les erreurs. La deuxième fonction sert à traîter les parenthèses. La troisième à vérifier les opérateurs.

La précédence des opératuers est totalement respectée.

Exemples d'évaluations de chaînes :
cos(45)^2+sin(45)^2 donne 1 (évident)
1+(6*(5/2)+8)*3 donne 70
exp(1) donne 2.718281828...
2*pi*4.5^2 donne 127.23..

N'hésitez pas à donner vos commentaires. J'espère que cette source pourra vous être utile.
Merci.

Source / Exemple :


Function a_EvalString(ByVal a$)
On Error GoTo Errh_a_Evalstring
Dim p As Integer, p2 As Integer, par As Integer, v2 As Single
Dim fct$, allfct$, i As Integer, found
a$ = LCase$(a$) 'Pour faciliter la recherche des fontions.
If a$ = "" Then
    a_EvalString = "ERREUR Vierge"
    Exit Function
End If
p = InStr(a$, "erreur")
If p <> 0 Then
    a_EvalString = Mid$(a$, p)
    Exit Function
End If
allfct$ = "int,abs,atn,cos,exp,fix,log,rnd,sgn,sin,sqr,tan"
For i = 1 To Len(allfct$) Step 4
    fct$ = Mid$(allfct$, i, 3)
    p = InStr(a$, fct$ + "(")
    If p <> 0 Then
        p2 = a_GetPosPar(a$, p + Len(fct$))
        If p2 = -1 Then
            a_EvalString = "ERREUR Par sur " + fct$
            Exit Function
        End If
        If Not A_verifop(Trim$(Left$(a$, p - 1)), 1) Or Not A_verifop(Mid$(a$, p2 + 1), 2) Then
            a_EvalString = "ERREUR opérateur"
        Else
            
            Select Case fct$
            Case "int"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Int(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            Case "abs"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Abs(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            Case "atn"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Atn(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            Case "cos"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Cos(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            Case "exp"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Exp(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            Case "fix"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Fix(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            Case "log"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Log(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            Case "rnd"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Rnd(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            Case "sgn"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Sgn(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            Case "sin"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Sin(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            Case "sqr"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Sqr(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            Case "tan"
                a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(Tan(a_EvalString(Mid$(a$, p + 1 + Len(fct$), p2 - p - 1 - Len(fct$))))) + Mid$(a$, p2 + 1))
            End Select
        End If
        Exit Function
    End If
Next i

p = InStr(a$, "(")
If p <> 0 Then
    p2 = a_GetPosPar(a$, p)
    If p2 = -1 Then
        a_EvalString = "ERREUR Parenthèses"
        Exit Function
    End If
    If Not A_verifop(Trim$(Left$(a$, p - 1)), 1) Or Not A_verifop(Mid$(a$, p2 + 1), 2) Then
        a_EvalString = "ERREUR opérateur"
    Else
        a_EvalString = a_EvalString(Left$(a$, p - 1) + Format$(a_EvalString(Mid$(a$, p + 1, p2 - p - 1))) + Mid$(a$, p2 + 1))
    End If
    Exit Function
End If
p = InStr(a$, "+")
If p <> 0 Then
    a_EvalString = a_EvalString(Left$(a$, p - 1)) + a_EvalString(Mid$(a$, p + 1))
    Exit Function
End If
p = InStr(2, a$, "-")
If p <> 0 Then
    allfct$ = "e-,*-,/-,^-"
    found = False
    For i = 1 To Len(allfct$) Step 3
        p2 = InStr(a$, Mid$(allfct$, i, 2))
        If p2 = p - 1 And p2 <> 0 Then
            found = True
        End If
    Next i
    If Not found Then
        If p > 1 Then
            a_EvalString = a_EvalString(Left$(a$, p - 1)) - a_EvalString(Mid$(a$, p + 1))
            Exit Function
        Else
            Stop
            'a_EvalString = -a_EvalString(Mid$(a$, p + 1))
            'Exit Function
        End If
    End If
End If
p = InStr(a$, "*")
If p <> 0 Then
    a_EvalString = a_EvalString(Left$(a$, p - 1)) * a_EvalString(Mid$(a$, p + 1))
    Exit Function
End If
p = InStr(a$, "\")
If p <> 0 Then
    a_EvalString = a_EvalString(Left$(a$, p - 1)) \ a_EvalString(Mid$(a$, p + 1))
    Exit Function
End If
p = InStr(a$, "^")
If p <> 0 Then
    a_EvalString = a_EvalString(Left$(a$, p - 1)) ^ a_EvalString(Mid$(a$, p + 1))
    Exit Function
End If

p = InStr(a$, "/")
If p <> 0 Then
    v2 = a_EvalString(Mid$(a$, p + 1))
    If v2 <> 0 Then
        a_EvalString = a_EvalString(Left$(a$, p - 1)) / v2
    Else
        a_EvalString = "ERREUR division par 0"
    End If
    Exit Function
End If

If a$ <> "" Then
    If a$ = "pi" Then
        a_EvalString = 4 * Atn(1)
    ElseIf a$ = "-pi" Then
        a_EvalString = -4 * Atn(1)
    ElseIf a$ = "e" Then
        a_EvalString = "2.7182818284590452353602874713527" 'exp(1)
    ElseIf a$ = "-e" Then
        a_EvalString = "-2.7182818284590452353602874713527"
    Else
        a_EvalString = CDbl(a$) 'Val(a$)
    End If
Else
    a_EvalString = "ERREUR Vierge"
End If
Exit Function
Errh_a_Evalstring:
    a_EvalString = "ERREUR"
End Function
Function a_GetPosPar(a$, p2)
Dim p As Integer, par As Integer
    
    p = p2
    par = 1
    Do
        p = p + 1
        Select Case Mid$(a$, p, 1)
        Case "(": par = par + 1
        Case ")": par = par - 1
        End Select
    Loop Until par = 0 Or p > Len(a$)
    If par <> 0 Then
        a_GetPosPar = -1
    Else
        a_GetPosPar = p
    End If
End Function
Function A_verifop(a$, flag)
Dim ok As Integer
a$ = Trim$(a$)
If a$ = "" Then
    A_verifop = True
    Exit Function
End If
ok = False
Select Case flag
Case 2
    Select Case Left$(a$, 1)
    Case "+", "-", "*", "/", "^", ")"
        ok = True
    End Select
Case 1
    Select Case Right$(a$, 1)
    Case "+", "-", "*", "/", "^", "("
        ok = True
    End Select
End Select
A_verifop = ok
If ok = False Then Stop
End Function

Conclusion :


Je remercie EbartSoft qui a mis le doigt sur une erreur, corrigée depuis.

Pour une representation de fonction cartésienne ou polaire, allez voir la source : 9770

Codes Sources

A voir également

Ajouter un commentaire Commentaires
Messages postés
2
Date d'inscription
mercredi 5 janvier 2011
Statut
Membre
Dernière intervention
6 janvier 2011

Bonjour,

Merci pour l'effort
Stp je voulais te demander si avec le meme algorithme
je pourrai avoir le meme résultat sous java
si c'est le cas est ce que ça vous dérange de me passer l'algo
parce ce que je maitrise pas l VB

merci d'avance
Messages postés
15
Date d'inscription
samedi 28 décembre 2002
Statut
Membre
Dernière intervention
17 août 2004

Merci pour ce code !!! Pour mes besoins il est super !!! Juste peut-être une modification pour le problème de 45/5/3 :
modifier la ligne p = InStr(a$, "/")
en p = InStrRev(a$, "/")
dans la fonction a_EvalString...

9/10
Messages postés
5
Date d'inscription
jeudi 26 juin 2003
Statut
Membre
Dernière intervention
25 juillet 2003

Bonjour cartvb.
Je suis d'accord pour la priorité gauche - droite mais pour le reste ...
exp(45) = 3,49 E+19 , et log(exp(45)) donne bien 45.
Le problème vient du fait que j'ai utilisé VAL dans la fonction au lieu de CDBL pour que la fonction tienne compte des paramètre régionaux comme expliquer par rené juste avant toi.
Messages postés
199
Date d'inscription
mercredi 23 avril 2003
Statut
Contributeur
Dernière intervention
25 mai 2017
9
réctification : 45/5/3=3 et non 1 (je m'en excuse)
Messages postés
199
Date d'inscription
mercredi 23 avril 2003
Statut
Contributeur
Dernière intervention
25 mai 2017
9
salut 0livier,
ta source est très interressante et je trouve que tu as de très bonnes idées.
Mais, ton évaluateur a le même problème que mon ancien évaluateur (n°8750) liée à l'ordre de calcul pour les opérateurs de même priorité. Tu le fais de droite à gauche au lieu de gauche à droite ce qui cause quelques surprises.
exemples : 5-4-1 donne 2 (au lieu de 0) car il est interprété comme 5-(4-1)
45/5/3 donne 27,0000006437302 (au lieu de 1)
un autre problème (plus délirant) exp(45) donne ...22 et ainsi log(exp(45)) donne 3 au lieu de 45
là tu dois te poser des questions.
allez 7/10 (Mention bien)
Afficher les 10 commentaires

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.