Microsoft 365 Isoler, convertir et calculer une chaîne de caractères entre parenthèses

manu_tella

XLDnaute Junior
Bonjour à tous,

Suite à un coup de main non négligeable des membres je reviens vers vous pour compléter mon code car je fais face a un use-case que je n'arrive pas à gérer.
Je cherche à traiter une chaîne de caractères bien spécifiquement avec le traitement des opérations entre parenthèses en priorité.
Je ne peux malheureusement pas partager le fichier car les données sont confidentielles mais je vais tenter d’être le plus clair possible dans la demande.

Au départ j'ai variable string type :

APS = (Banane OR fraise) AND NOT (pomme OR Groseille)

avec une matrice qui fonctionne j'arrive a convertir mes fruits et mes légumes en un expression de type:

APS = (1 OR 0) AND NOT (0 OR 1)

et là ou je remplaçais les OR et les AND par des opérations mathématiques je me rends compte que le le cas du AND NOT pose problème, il me faudrait d'abord calculer ce qui est présent dans la parenthèse.
j'imaginais d'abord remplacer les OR et les AND par des + et des * sans tenir compte des AND NOT ou OR NOT
pour arriver à cette étape intermédiaire:
APS = (1 + 0) AND NOT (0 + 1)
APS = (1) AND NOT (1)

comment est-il possible de créer un calcul intermédiaire dans mon code pour arriver à cette étape ? je pensais passer par un split et en faisant une évaluation de chaque calcul entre parenthèse et ainsi à la fin, remplacer les chaines AND NOT (1) ou AND NOT (0) par * 0 et * 1?

d'avance merci pour votre aide

manu
 
Solution
mais la contrainte du "NOT" suivi d'une parenthèse n'est pas vraie dans tous les cas
Alors dans ce fichier (3) la macro ajoute les parenthèses après "NOT" quand il n'y en a pas :
VB:
Sub Calcul()
Dim P As Range, tablo, i&, txt$, s, j%, v As Variant
Set P = [A15].CurrentRegion.Resize(, 2)
With [A1].CurrentRegion.Resize(, 4)
    tablo = .Value 'matrice, plus rapide
    For i = 2 To UBound(tablo)
        txt = tablo(i, 2)
        s = Split(Replace(Replace(Replace(Replace(Replace(txt, "AND", ""), "OR", ""), "NOT", ""), "(", ""), ")", ""))
        For j = 0 To UBound(s)
            v = Application.VLookup(s(j), P, 2, 0)
            If Not IsError(v) Then txt = Replace(txt, s(j), IIf(LCase(v) = "x", 1, 0))
        Next j
        txt =...

dysorthographie

XLDnaute Accro
essais comme ça!
VB:
Function EvaluationCode(Optional Variable As String, Optional Equation As String)
With CreateObject("MSScriptControl.ScriptControl")
    .Language = "VbScript"
    .ExecuteStatement Variable & vbCrLf & "V=" & Equation
    EvaluationCode = .Eval("v")
End With
End Function
 

dysorthographie

XLDnaute Accro
si des âmes charitables veulent bien évaluer ce code, d'avance merci!
Système Mac s'abstenir.

VB:
Sub test()
'(1 OR 0) AND NOT (0 OR 1)
MsgBox EvaluationCode("Banane=1:fraise=0:pomme=0:Groseille=1", "(Banane OR fraise) AND NOT (pomme OR Groseille)")
MsgBox EvaluationCode(Equation:="(1 OR 0) AND NOT (0 OR 1)")
End Sub
Function EvaluationCode(Optional Variable As String, Optional Equation As String)
With CreateObject("ScriptControl")
    .Language = "VbScript"
    .ExecuteStatement Variable & vbCrLf & "V=" & Equation
    EvaluationCode = .Eval("v")
End With
End Function
 

dysorthographie

XLDnaute Accro
une autre version de EvaluationCode
VB:
Sub test()
MsgBox EvaluationCode("(1 OR 0) AND NOT (0 OR 1)")
End Sub

Function EvaluationCode(Equation As String) as integer
With CreateObject("Adodb.Connection")
    .Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0;HDR=No;"""
    With .Execute("SELECT " & Equation & " AS Resulta;")
        If Not .EOF Then EvaluationCode = Abs(.fields("Resulta"))
        .Close
    End With
    .Close
End With
End Function
 
Dernière édition:

job75

XLDnaute Barbatruc
Bonjour manu_tella, dysort, le forum,

Oui dysort maintenant ça fonctionne :
VB:
Sub project_filtering()
Dim t#, F As Worksheet, P As Range, i As Variant, c As Range, tablo
t = Timer
Application.ScreenUpdating = False
Set F = Sheets("DIV")
Set P = [A3].CurrentRegion.Offset(1)
P.Name = "P" 'plage nommée
P.Columns(2).Copy P.Columns(3)
P.Columns(4) = ""
'---3ème colonne---
i = Application.Match([A1], F.Rows(5), 0)
If IsError(i) Then Exit Sub
P.Columns(3).Replace "~*", 1, xlPart
For Each c In F.Columns(2).SpecialCells(xlCellTypeConstants)
    If c.Row > 6 Then P.Columns(3).Replace c, IIf(c(1, i - 1) = "", 0, 1)
Next
'---4ème colonne---
tablo = P.Columns(3).Resize(, 2) 'matrice, plus rapide
With CreateObject("Adodb.Connection")
    .Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0;HDR=No;"""
    For i = 1 To UBound(tablo) - 1
        With .Execute("SELECT " & tablo(i, 1) & " AS Resulta;")
            If Not .EOF Then tablo(i, 2) = Abs(.Fields("Resulta"))
            .Close
        End With
    Next i
    .Close
End With
P.Columns(3).Resize(, 2) = tablo
Application.ScreenUpdating = True
MsgBox P.Rows.Count - 1 & " lignes traitées en " & Format(Timer - t, "0.00 \sec")
End Sub
Chez moi la durée d'exécution est de 4,5 secondes sur 6200 lignes.

A+
 

Pièces jointes

  • Classeur ADO(1).xlsm
    153.5 KB · Affichages: 2

manu_tella

XLDnaute Junior
Bonjour à tous les deux, bonjour le forum

Encore merci pour votre aide
Apres quelques adaptations liées à mon fichier le dernier code fonctionne.
Il n'est pas aussi rapide que le votre (4342 lignes en 55 secondes) mais ce n'est pas un souci.

questions subsidiaires pour :
- comment adapte t-on à une ligne la commande:
tablo = P.Columns(3).Resize(, 2)? => j'ai essayé P.Rows(3).Resize(, 2). j'imagine qu'il faut passer par "transpose"?

- comment récupérer uniquement la seconde colonne du tablo? pour dans un cas la coller dans une colonne définie (et aussi en rapport avec la question précédente, coller la colonne 2 du tablo dans une ligne définie?)?

encore merci pour le temps que vous me consacrez.

manu
 

job75

XLDnaute Barbatruc
J'aimerais bien connaître aussi la durée d'exécution chez vous de ma macro du post # 24 :rolleyes:

Que viennent faire dans ce problème vos questions subsidiaires ?

Si vous voulez traiter les lignes 3 et 4 de la plage P :
VB:
tablo = P.Rows(3).Resize(2)
 

manu_tella

XLDnaute Junior
Bonjour job75,

Le code du post24 a un temps d’exécution similaire (de l'ordre de 45/50 secondes). J'imagine que les performances de ma machine ne sont pas à la hauteur des vôtres.

Le code du post 24, fonctionne bien mais si par hasard une erreur arrive, il faut ouvrir l’éditeur et supprimer manuellement les lignes de codes afin de remettre le module dans son état initial (et ce, à la ligne près).
Une erreur pourrait éventuellement due au mauvais remplacement d'une chaîne de caractères (par exemple non définie dans la diversité).

Le dernier code permet une gestion plus aisée des erreurs car il stop, ouvre la fenêtre de debug mais ne nécessite pas de remanier les lignes.

Je viens de finir l'adaptation et je suis sur:
analyse des lignes => 4342 lignes en 60.51 sec
analyse des colonnes => 7006 colonnes en 101 sec

ces temps ne tiennent pas compte de la conversion de la 3eme colonne que j'ai mis dans un module à part.

Il me reste à gérer les erreurs en intégrant un message, en citant les refs de la ligne/colonne en question, en forçant une valeur à 0 et enfin continuer l’exécution du code.

merci pour tout

manu
 

manu_tella

XLDnaute Junior
Oui ça correspond parfaitement au besoin
Merci beaucoup à tous les 2, avec tous ces échanges j'ai pu non seulement aboutir au résultat souhaité mais aussi progresser en vba même si je suis conscient des progrès qu'il me reste à faire :)

Même si le code semble long à s’exécuter chez moi, ce n'est rien par rapport à la méthode que je devais adopter avant. Je tenterai sur mon PC perso.

Infiniment merci pour vos posts et de manière certaine, à très bientôt pour d'autres questions :)

manu
 

Discussions similaires

Statistiques des forums

Discussions
312 098
Messages
2 085 265
Membres
102 844
dernier inscrit
atori2