[REGEX] Recherche Patten de capture, un défi ?

Résolu
NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024 - 11 oct. 2023 à 20:43
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 - 27 févr. 2024 à 23:34

Bonjour à tous,

J'essaie vainement de créer un Patten de capture.

Voici la chaine concernée:

85339147802789523626847310205970239AR2950793415PC7098624031

De cette chaine, j'aimerais capturer les caractères qui sont après 10 jusqu'à AR.

Soit : 205970239

Les contraintes:

Après 85 il y a toujours 14 caractères variable.

Après 36 il y a toujours 6 caractères variable.

Le nombre de caractères entre 10 et AR et compris entre 1 et 20 caractères variable.

Après 29 il y a toujours 6 caractères variable.

Après 15 le nombre de caractères et compris entre 1 et 20 caractères variable.

85, 36, le couple 10 et AR, 29 et 15 serons toujours présent.

85 est toujours en début de chaine.

Les positions de 36, du couple 10 et AR, 29 et 15 peuvent changer

Dans ma chaine d'exemple nous avons:

85, 36, le couple 10 et AR, 29 et 15

Ça pourrait être:

85, 29, le couple 10 et AR, 15 et 36

Ou encore:

85, le couple 10 et AR, 15, 36, 29

J'espère être assez claire et que vous pourrez m'aider ?

142 réponses

Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
11 oct. 2023 à 20:59

Bonsoir

question bête, si ce qui compte ce sont les caractères entre 10 et AR, le reste (85, 15, 36, 29) a-t-il vraiment de l'importance ?

Par exemple, existe-t-il des séquences contenant 10 et AR mais sans 85, 15, 36, 29 et qui du coup ne serait pas à capturer ?


1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
11 oct. 2023 à 21:58
(?<=10).{1,20}(?=AR)

Un exemple ici https://regex101.com/r/Q8ToAf/1

La dernière ligne n'est pas capturée, car il y a 21 caractères entre 10 et AR


1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
13 oct. 2023 à 07:10

Le problème à découper la séquence par partie est le risque de collision.

Par exemple, s'il y a 11 dans les caractères qui suivent le 01, la capture commencera là. Cf cet exemple, les 4 premières lignes sont celles de ton code et la dernière est la précédente que j'ai modifiée pour illustrer.

À mon sens, il faut essayer de trouver un(des) pattern qui t'immunise de ce risque.

  • soit un pattern global (ha mon avis le plus sûr, mais pas le plus simple)
  • soit des patterns plus "safes", par exemple 11 et 17 sont des dates, donc utiliser des regex qui excluent les combinaisons de chiffres qui ne représentent pas une date, et après les 6 chiffres, il ne peut y avoir qu'un 11, un 17, un 10, un 21 ou la fin de chaine. Mais malgré ça, la collision n'est pas totalement exclue

Je n'aurais pas trop le temps de me pencher sérieusement sur la question aujourd'hui. J'y regarderai ce week-end.


1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
14 oct. 2023 à 08:07

Ce qui ne marche pas en vba, c'est (au moins)  les groupes nommés.

Ça on peut s'en passer, il faut juste savoir le numéro du groupe qu'on cherche.

Il faut voir si les options sont acceptées.

Je n'ai pas fait de tests approfondis. Mais j'aurais un peu de temps ce matin.


Le risque avec les "ou" comme tu l'as fait c'est de faire matcher une séquence avec des doublons, mais plus haut tu indiques qu'il ne peut pas y en avoir. Donc ça ne serait pas un problème. Il faut juste en être conscient. C'est d'ailleurs sur une combinaison de ou que je voulais plancher.

Et à priori, comme tu as inclus la balise 01 dans le ou, ça doit pouvoir matcher si elle n'est pas en première position.


1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
14 oct. 2023 à 09:28

Ha et t'as mis des "anti" préfixes, ça non plus ça ne doit pas marcher en VBA.

0

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

Posez votre question
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
14 oct. 2023 à 11:11

Au temps pour moi, j'avais pas déclaré les variable d'itération des for

Option Explicit

Sub TestNeriXs()
Dim pattern01, pattern11, pattern17, pattern10, pattern21, pattern, code, capture, balise, resultat As String
Dim regex, matches, Match As Object
Dim codes As Variant
Dim i As Integer

codes = Array("0100883873867792112209271723092710220927GS21PC23713163", "01008838738677921723092710220927GS21PC23713163GS11220927", "0100883873867792112209271723092710220927GS21PC23713163", "01034009301383801726013110DB20323GS2195918770106437", "01034009301884081726060010ABS3514", "01034009346722482110045423841916GS10X09897AGS17260430")

Set regex = New RegExp

pattern01 = "^(01.{14})"
pattern11 = "(11\d{6})"
pattern17 = "(17\d{6})"
pattern10 = "(10.{1,20}?)(?:GS|$)"
pattern21 = "(21.{1,20}?)(?:GS|$)"

pattern = pattern01 + "(?:" + pattern11 + "|" + pattern17 + "|" + pattern10 + "|" + pattern21 + ")+$"

regex.pattern = pattern
For Each code In codes
    If (regex.Test(code)) Then
        Set matches = regex.Execute(code)
        For Each Match In matches
            For i = 0 To Match.SubMatches.Count - 1
                capture = Match.SubMatches.Item(i)
                balise = Left(capture, 2)
                Select Case balise
                    Case "01"
                        resultat = balise + ": " + Right(capture, 14) + ", "
                
                    Case "11", "17"
                        resultat = resultat + balise + ": " + Right(capture, 6) + ", "
                
                    Case "10", "21"
                        resultat = resultat + balise + ": " + Right(capture, Len(capture) - 2) + ", "
                End Select
            Next
            Debug.Print code
            Debug.Print resultat
        Next
    End If
Next
End Sub

1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
14 oct. 2023 à 11:32

Étonnant, tu n'as pas inclus les regex dans ton projet....


1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
14 oct. 2023 à 20:24

Alors, le pourquoi du comment.

D'abord, je t'ai posé plein de question pour cerner le besoin, parce que forcément, je n'ai pas toute ton expérience sur le sujet et pour poser des hypothèses réalistes, il me fallait des infos.

Donc forcément, c'était un peu long.

Ensuite, regex VBA => exit les préfixes/suffixes (qu'ils soient obligés ou interdits) et les groupes nommés.

Pour les groupes, il faut faire en sorte de savoir de quelles balises on parle, et pour ça mon axiome de départ a été : la balise fait partie de la capture et on trie ensuite grâce aux 2 premiers caractères.

Pour les pré/suffixes, il faut trouver d'autres syntaxes.

Mes hypothèses ont été

Balise Position Valeur
01 début 14 caractères
11 n'importe où 6 chiffres
17 n'importe où 6 chiffres
10 n'importe où 1 à 20 caractères + GS ou fin de séquence
21 n'importe où 1 à 20 caractères + GS ou fin de séquence

À partir de là, j'ai tenté un premier jeu de patterns, qui s'est révélé bon pour les 3 premiers.

Pattern unitaire Signification
^(01.{14}) Début de séquence, groupe qui capture la balise et 14 caractères
(11\d{6}) Groupe qui capture la balise et 6 chiffres
(17\d{6})

Mais ça ne marchait pas pour les balises 10 et 21.

Sur tes codes barres de test, il y en avait un où il y avait un 10 et un 21 à la suite (ou inversement) dont qui totalisait moins de 20 caractères. Du coup, il n'y avait qu'une capture qui s'est arrêtée au 2eme GS. Du coup, il fallait ajouter une contrainte pour que la capture soit la plus courte possible (en ajoutant ? après {1,20} )

Pattern unitaire Signification
^(01.{14}) Début de séquence, groupe qui capture la balise et 14 caractères
(11\d{6}) Groupe qui capture la balise et 6 chiffres
(17\d{6})
(10.{1,20}?)(?:GS|$) Groupe qui capture la balise, puis de 1 à 20 caractères, mais le plus court possible, puis GS ou fin de séquence qui ne sont pas dans le groupe
(21.{1,20}?)(?:GS|$)

Ensuite, il fallait mettre tout ça dans une seule regex, avec des ou comme tu l'avais présenti, sauf la balise 01 qui est toujours présent et au début de la séquence, donc ne doit pas être dans le "ou".

Ensuite ce qui est dans le "ou" arrive plusieurs fois, mais on ne sait pas dire combien (donc un + comme quantificateur).

Enfin la capture va jusqu'à la fin de la séquence.

Si on appelle pXX chaque pattern unitaire ça donne

p01(?:p11|p17|p10|p21)+$

Après avoir validé ça sur regex101, je l'ai transposé en VBA.

J'ai gardé l'idée des patterns unitaires pour plus de lisibilité et surtout c'est plus facile de retoucher un pattern unitaire si besoin qu'une grande regex.

Ce qui a donné ce code, que j'ai commenté

Sub TestNeriXs()
Dim pattern01, pattern11, pattern17, pattern10, pattern21, pattern, code, capture, balise, resultat As String
Dim regex, matches, Match As Object
Dim codes As Variant
Dim i As Integer

'mise de plusieurs codes de test dans un tableau
codes = Array("0100883873867792112209271723092710220927GS21PC23713163", "01008838738677921723092710220927GS21PC23713163GS11220927", "0100883873867792112209271723092710220927GS21PC23713163", "01034009301383801726013110DB20323GS2195918770106437", "01034009301884081726060010ABS3514", "01034009346722482110045423841916GS10X09897AGS17260430")

Set regex = New RegExp

'écriture des patterns unitaires
pattern01 = "^(01.{14})"
pattern11 = "(11\d{6})"
pattern17 = "(17\d{6})"
pattern10 = "(10.{1,20}?)(?:GS|$)"
pattern21 = "(21.{1,20}?)(?:GS|$)"

'fusion du pattern complet
pattern = pattern01 + "(?:" + pattern11 + "|" + pattern17 + "|" + pattern10 + "|" + pattern21 + ")+$"

regex.pattern = pattern

'test de chaque code du tableau
For Each code In codes
    'on vérifie d'abord que la regex matche
    If (regex.Test(code)) Then
        'si oui, on recoupère les datas
        'comme je ne savais pas si tu récupères les codes un à un ou en lot (dans un fichier par exemple),
        'je suis parti du principe qu'il pouvait y avoir plusieurs matches
        Set matches = regex.Execute(code)
        
        For Each Match In matches
            'pour chaque match, on récupère les groupes
            For i = 0 To Match.SubMatches.Count - 1
                capture = Match.SubMatches.Item(i)
                'on extrait la balise pour affecter le résultat comme il faut
                balise = Left(capture, 2)
                'j'ai choisi un select case, car ça se prête bien à la situation
                Select Case balise
                    Case "01"
                        resultat = balise + ": " + Right(capture, 14) + ", "
                
                    Case "11", "17"
                        resultat = resultat + balise + ": " + Right(capture, 6) + ", "
                
                    Case "10", "21"
                        resultat = resultat + balise + ": " + Right(capture, Len(capture) - 2) + ", "
                End Select
            Next
            'on imprime le résultat dans la console
            Debug.Print code
            Debug.Print resultat
        Next
    End If
Next
End Sub

1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
14 oct. 2023 à 20:37

Que l'on peut modifier par exemple comme ça

Option Explicit

Sub TestNeriXs()
Dim pattern01, pattern11, pattern17, pattern10, pattern21, pattern, code, capture, balise, resultat, gtin, dateProd, dateExpi, numLot, numSerie As String
Dim regex, matches, Match As Object
Dim codes As Variant
Dim i As Integer

'mise de plusieurs codes de test dans un tableau
codes = Array("0100883873867792112209271723092710220927GS21PC23713163", "01008838738677921723092710220927GS21PC23713163GS11220927", "0100883873867792112209271723092710220927GS21PC23713163", "01034009301383801726013110DB20323GS2195918770106437", "01034009301884081726060010ABS3514", "01034009346722482110045423841916GS10X09897AGS17260430")

Set regex = New RegExp

'écriture des patterns unitaires
pattern01 = "^(01.{14})"
pattern11 = "(11\d{6})"
pattern17 = "(17\d{6})"
pattern10 = "(10.{1,20}?)(?:GS|$)"
pattern21 = "(21.{1,20}?)(?:GS|$)"

'fusion du pattern complet
pattern = pattern01 + "(?:" + pattern11 + "|" + pattern17 + "|" + pattern10 + "|" + pattern21 + ")+$"

regex.pattern = pattern

'test de chaque code du tableau
For Each code In codes
    'on vérifie d'abord que la regex matche
    If (regex.Test(code)) Then
        'si oui, on recoupère les datas
        'comme je ne savais pas si tu récupères les codes un à un ou en lot (dans un fichier par exemple),
        'je suis parti du principe qu'il pouvait y avoir plusieurs matches
        Set matches = regex.Execute(code)
        
        For Each Match In matches
            'pour chaque match, on récupère les groupes
            For i = 0 To Match.SubMatches.Count - 1
                capture = Match.SubMatches.Item(i)
                'on extrait la balise pour affecter le résultat comme il faut
                balise = Left(capture, 2)
                'j'ai choisi un select case, car ça se prête bien à la situation
                Select Case balise
                    Case "01"
                        gtin = Right(capture, 14)
                        resultat = "(01)" + gtin
                
                    Case "11"
                        dateProd = Right(capture, 6)
                        resultat = resultat + "(11)" + dateProd
                        
                    Case "17"
                        dateExpi = Right(capture, 6)
                        resultat = resultat + "(17)" + dateExpi
                        
                    Case "10"
                        numLot = Right(capture, Len(capture) - 2)
                        resultat = resultat + "(10)" + numLot
                        
                    Case "21"
                        numSerie = Right(capture, Len(capture) - 2)
                        resultat = resultat + "(21)" + numSerie
                End Select
            Next
            'on imprime le résultat dans la console
            Debug.Print resultat
            Debug.Print "(01) GTIN de l’article: " + gtin
            Debug.Print "(11) Date de production: " + dateProd
            Debug.Print "(17) Date d'expiration : " + dateExpi
            Debug.Print "(10) Numéro de lot: " + numLot
            Debug.Print "(21) Numéro de série: " + numSerie
        Next
    End If
Next
End Sub

1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
15 oct. 2023 à 15:20

Le pattern01 part du principe que le code barre commence par la balise 01.

Si une balise FNC1 est présente, ça n'est plus le cas et donc ça ne matche pas.

Option 1 enlever le "^" au début du pattern et la capture commencera au premier 01. Mais si tu as un code en entrée qui ne correspond pas aux autres balises, ça pourrait mettre le bazar.

Option 2, modifier le pattern01 pour qu'il accepte ces balises en option, pas testé, mais à priori ça devrait ressembler à 

"^(?:](?:C1|e0|d2|Q3|J1))?(01.{14})"

1

Vu ton autre question, j'ai utilisé une classe.

Il faut ajouter un module de classe, le renommer UnCode et copier coller ça dedans

'Champs utiles
Public Capture As String

Public Balise As String

Public LeCode As String

Public Position As Integer

'Initialise l'instance de l'objet UnCode
Public Sub Init(LaCapture As String, LaPosition As Integer)
    Capture = Replace(Replace(LaCapture, "(", ""), ")", "")
    Position = LaPosition
    Balise = Left(Capture, 2)
    LeCode = Right(Capture, Len(Capture) - 2)
End Sub


'Méthode qui retourne un texte sous la forme "(Balise)LeCode"
Public Function Texte() As String
    Texte = "(" & Balise & ")" & LeCode
End Function

'Méthode qui retourne un texte sous la forme "(Balise) Description : LeCode"
Public Function Description() As String
    Dim madescription As String
    
    Select Case Balise
        Case "01"
            madescription = "(01) GTIN de l’article: "
    
        Case "11"
            madescription = "(11) Date de production: "
            
        Case "17"
            madescription = "(17) Date d'expiration : "
            
        Case "10"
            madescription = "(10) Numéro de lot: "
            
        Case "21"
            madescription = "(21) Numéro de série: "
        
    End Select
           
    Description = madescription + LeCode
End Function

Ensuite, il faut modifier la lecture comme ça

Function TestNeriXs(code As String) As String
Dim pattern01, pattern11, pattern17, pattern10, pattern21, pattern, ligne1, ligne2 As String
Dim regex, matches, Match As Object
Dim i, Position As Integer
Dim resultats As Dictionary
Dim unCode As unCode

Set regex = New RegExp

'écriture des patterns unitaires
pattern01 = "^(?:](?:C1|e0|d2|Q3|J1))?(\(?01\)?.{14})(?:GS|\x1d)?"
pattern11 = "(\(?11\)?\d{6})(?:GS|\x1d)?"
pattern17 = "(\(?17\)?\d{6})(?:GS|\x1d)?"
pattern10 = "(\(?10\)?.{1,20}?)(?:GS|$|\x1d|\()"
pattern21 = "(\(?21\)?.{1,20}?)(?:GS|$|\x1d|\()"

'fusion du pattern complet
pattern = pattern01 + "(?:" + pattern11 + "|" + pattern17 + "|" + pattern10 + "|" + pattern21 + ")+$"

regex.pattern = pattern

'valeur par défaut si la regex ne matche pas
ligne1 = "Code incorrect"

'on vérifie d'abord que la regex matche
If (regex.test(code)) Then
    'si oui, on recoupère les datas
    'comme je ne savais pas si tu récupères les codes un à un ou en lot (dans un fichier par exemple),
    'je suis parti du principe qu'il pouvait y avoir plusieurs matches
    Set matches = regex.Execute(code)
    
    For Each Match In matches
        ligne1 = ""
        ligne2 = ""
        
        Set resultats = New Dictionary
        
        Set unCode = New unCode
        unCode.Init Match.SubMatches.item(0), 1
        resultats.Add "01", unCode

        'on ajoute les submatches 1 à n
        For i = 1 To Match.SubMatches.Count - 1
            Position = InStr(code, Match.SubMatches.item(i))
            If Position > 1 Then 'les groupes qui ne macthent rien sont vides et ça donne une position à 1
                Set unCode = New unCode
                unCode.Init Match.SubMatches.item(i), Position
                resultats.Add Format(Position, "00"), unCode
            End If
        Next
        
        'on repart de la position 1
        i = 1
        Do
            Set unCode = resultats.item(Format(i, "00"))
            
            'la ligne1 est la reconstitution du code avec les parenthèses, la ligne2 les descriptions
            ligne1 = ligne1 + unCode.Texte()
            ligne2 = ligne2 + vbCrLf + unCode.Description()
            
            
            i = i + Len(unCode.Capture) 'on passe à la position suivante à partir de laquel il faut chercher une clé

            'on vérifie que la clésuivante existe
            Do While Not resultats.Exists(Format(i, "00")) And i < Len(code)
                i = i + 1 'il faut incrémenter pour passer les GS et les ( qui ont été ignorés
            Loop
        Loop While i < Len(code) 'quand on a atteint la taille du code (pour GS...), c'est qu'on a fini
    Next
End If
TestNeriXs = ligne1 + ligne2
End Function

Avec ce code de test

Sub test()
Dim codes, code As Variant
codes = Array("0107332414124359210000107668GS11210208", "(01)00843997013703(11)210601(17)230601(21)3000105704", "(01)00843997013703(11)210601(17)230601(10)54gp75P(21)3000105704", "(01)00843997013703(11)210601(10)54gp75P(17)230601(21)3000105704")

For Each code In codes
    Debug.Print (code + " => ")
    Debug.Print (TestNeriXs(CStr(code)))
    Debug.Print ("")
Next
End Sub

J'obtiens

0107332414124359210000107668GS11210208 => 
(01)07332414124359(21)0000107668(11)210208
(01) GTIN de l’article: 07332414124359
(21) Numéro de série: 0000107668
(11) Date de production: 210208

(01)00843997013703(11)210601(17)230601(21)3000105704 => 
(01)00843997013703(11)210601(17)230601(21)3000105704
(01) GTIN de l’article: 00843997013703
(11) Date de production: 210601
(17) Date d'expiration : 230601
(21) Numéro de série: 3000105704

(01)00843997013703(11)210601(17)230601(10)54gp75P(21)3000105704 => 
(01)00843997013703(11)210601(17)230601(10)54gp75P(21)3000105704
(01) GTIN de l’article: 00843997013703
(11) Date de production: 210601
(17) Date d'expiration : 230601
(10) Numéro de lot: 54gp75P
(21) Numéro de série: 3000105704

(01)00843997013703(11)210601(10)54gp75P(17)230601(21)3000105704 => 
(01)00843997013703(11)210601(10)54gp75P(17)230601(21)3000105704
(01) GTIN de l’article: 00843997013703
(11) Date de production: 210601
(10) Numéro de lot: 54gp75P
(17) Date d'expiration : 230601
(21) Numéro de série: 3000105704
1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
29 oct. 2023 à 20:32

Je crois que pour les patterns regroupés, j'y suis.

La classe modifiée comme suit

'Champs utiles
Public AI As String

Public Code As String


'Initialise l'instance de l'objet UnCode
Public Sub Init(LaBalise As String, LeCode As String)
    AI = LaBalise
    Code = LeCode
End Sub


'Méthode qui retourne un texte sous la forme "(Balise)LeCode"
Public Function Texte() As String
    Texte = "(" & AI & ")" & Code
End Function

'Méthode qui retourne un texte sous la forme "(Balise) Description : LeCode"
Public Function Description() As String
    Dim madescription As String
    
    Select Case AI
        Case "01"
            madescription = "(01) GTIN de l’article: "
    
        Case "11"
            madescription = "(11) Date de production: "
            
        Case "17"
            madescription = "(17) Date d'expiration : "
            
        Case "10"
            madescription = "(10) Numéro de lot: "
            
        Case "21"
            madescription = "(21) Numéro de série: "
        
        Case "91"
            madescription = "(91) InfosInternes: "
            
    End Select
           
    Description = madescription + Code
End Function

Le code de déchiffrement comme suit

Function TestNeriXs4(Code As String) As String
Dim fnc1, gs, caracteresOK, pattern, ligne1, ligne2 As String
Dim regex, Match As Object
Dim i As Integer
Dim resultats As Collection
Dim unCode As unCode
Dim patterns As Variant
Dim boucleOut As Boolean

Set regex = New RegExp

'écriture des patterns unitaires
gs = "(\x1d|\()?" 'quand c'est peut-être
fnc1 = "(\x1d|$|\()" 'quand c'est obligé
caracteresOK = "[\x21-\x22\x25-\x3F\x41-\x5A\x5F\x61-\x7A]"

'on met les patterns unitaires dans un tableau
patterns = Array("(?:](?:C1|e0|d2|Q3|J1))?\(?(01)\)?(" + caracteresOK + "{14})" + gs, _
            "\(?(1[123567])\)?(\d{6})" + gs, _
            "\(?(10)\)?(" + caracteresOK + "{1,20}?)" + fnc1, _
            "\(?(21)\)?(" + caracteresOK + "{1,20}?)" + fnc1 _
            )
'"(\(?9[1-9]\)?" + caracteresOK + "{0,90})" + fnc1 _

'valeur par défaut si la regex ne matche pas
ligne1 = "Code incorrect"
ligne2 = ""
Set resultats = New Collection

Do
    boucleOut = False
    For Each pattern In patterns
        'on teste chaque pattern pour le début du code
        regex.pattern = "^" + pattern
        If (regex.Test(Code)) Then
            boucleOut = True
            ligne1 = ""
            'si ça marche, on extrait la partie
            Set Match = regex.Execute(Code)(0)
    
            Set unCode = New unCode
            unCode.Init Match.SubMatches(0), Match.SubMatches(1)
            resultats.Add unCode
            
            'on enlève ce qu'on vient de traiter
            Code = Replace(Code, Match.Value, "")
            
            'et on recommence
            Exit For
        End If
    Next
    
Loop While Len(Code) > 0 And boucleOut 'si boucleOut vaut false c'est qu'on vient de faire un tour complet et qu'on est sur un cas imprévu

If boucleOut = False Then
    ligne1 = "Erreur data imprévue" + vbCrLf
End If

For i = 1 To resultats.Count
    Set unCode = resultats(i)
    ligne1 = ligne1 + unCode.Texte
    ligne2 = ligne2 + vbCrLf + unCode.Description
Next
TestNeriXs4 = ligne1 + ligne2
End Function

Pour l'instant, exprès j'ai exclu 9X

 Et le code de test

Sub Test()
Dim codes() As Variant
Dim Code As Variant
'mise de plusieurs codes de test dans un tableau
codes = Array("(01)00843997013703(11)210601(17)230601(21)3000105704", "010088483808258821DE7840AL79" + Chr(29) + "91867031", "0107332414124359210000107668" + Chr(29) + "11210208", "(01)00843997013703(11)210601(17)230601(10)54gp75P(21)3000105704", "(01)00843997013703(11)210601(10)54gp75P(17)230601(21)3000105704", "]C10100883873867792112207071723070710220707" + Chr(29) + "21PC22412085")

For Each Code In codes
    Debug.Print (Code)
    Debug.Print (TestNeriXs4(CStr(Code)))
    Debug.Print ("")
Next
    

End Sub

Dans lequel, d'une part GS n'apparait plus en texte mais \x21, et d'autre part, il y a un AI 91.

Je m'explique, je ne teste plus le code entier, mais juste le début pour un pattern, puis le suivant, puis le suivant etc..

Quand ça matche, je supprime la capture du code jusqu'à la fin.

Le risque, c'est de tomber sur un cas imprévu et de boucler à l'infini, j'ai donc mis un garde-fou et je le teste avec un AI 91.


Maintenant, on peut se pencher sur les 2 problèmes suivants

  • les AI à plus de 2 chiffres
  • la méthode Description que tu ne vas pas coder avec 500 Case

1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
29 oct. 2023 à 20:45

Dans ton tableau #72 tu as marqué dans le groupe 13 que fnc1 est requis.

Hors, je regarde au hasard, cette page https://www.gs1.org/standards/barcodes/application-identifiers à l'onglet 13, l'AI 3630 et FNC1 n'est pas requis.

Je ne sais pas si c'est la seule erreur, mais il va falloir revoir ce tableau.

0
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
2 nov. 2023 à 18:46

Bonsoir,

en effet, il faut être très vigilant avec les parenthèses (la preuve....)

En regex, elles délimitent un groupe, ce groupe peut être

  • un groupe de capture "SubMatch en VBA"
    ab(.+)ba
    , va créer une capture de tout ce qu'il y a entre ab et ba.
  • un groupe "non capturant", par exemple pour borner un ou,
    ab(?:12|21)ba
    matchera ab12ba ou ab21ba et "SubMatchera" 12 ou 21

J'ai basé le traitement actuel sur le fait qu'une SubMatch sera l'AI et l'autre la description.

Mais les AI peuvent être elles-mêmes entourés de parenthèses.

Il faut donc encadrer le groupe de capture de l'AI de parenthèses échapées et optionnelle.

Ce qui pour l'AI 1234 donne 

\(?(1234)\)?

Teste tes patterns sur regex101, tu vois le résultat en direct, tu as le détail des groupes de captures

Je te conseille de commencer par valider les fusions d'AI, puis de les entourer d'un groupe de capture et des parenthèses optionnelles.


1
NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024 1
2 nov. 2023 à 19:43

Citation:
Je te conseille de commencer par valider les fusions d'AI.

Réponse:
Je ne vois pas trop comment valider ces groupes de fusion avec certitude.

Quels conseils me donnerais-tu pour être le plus juste?

Les paramètre que j'ai appliqué sont:
FNC requis ou pas, Pattern identique.

0
NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024 1 > NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024
3 nov. 2023 à 00:26

Tu as bien fait d'insister pour la justesse des groupes !

J'avais oublié un pattern "^X(\d{0,6})$" soit 10 AI qui n'étaient pas dans le bon groupe.

Soit 3950 à 3959.

3 AI dans un mauvais groupe, car requières une balise de fin.

Soit 4326, 7006, 8005.

Nouvelle version : Groupe-Pattern-V3

J'ai séparé Les Ai 01 et 02 comme tu me l'as rappelé "01 et éventuel FNC au début".

0
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
8 nov. 2023 à 07:30

Bonjour 

tu peux utiliser une Collection 


1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
19 nov. 2023 à 08:59
Url = "https://id.gs1.org/" + primaryKey + keyQualifier
If dataAttribute <> "" Then
    Url = Url + "?" + dataAttribute
End If

1
NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024 1
19 nov. 2023 à 10:57

OK, c'est compris.
Je faisais une fixation et m'acharnais à vouloir absolument apporter la modification sur la partie de construction selon les groupes d'AI.
Pourtant mon pattern agissait bien sur l'url final, là c'est la même chose.
Désolé et merci pour la solution finale

0
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
20 janv. 2024 à 12:59

Pas testé, mais un truc dans le genre

Dans UnCode, j'ai modifié (et regroupé) le traitement des 3 AI en question

        Case "22" 'prio 1
            madescription = "(22) VARIANTE PRODUIT: "
            IsPriorityKeyQualifier = True
                                  
        Case "10" 'prio 2
            madescription = "(10) N° LOT: "
            IsPriorityKeyQualifier = True
            
        Case "21" 'prio 3
            madescription = "(21) N° SÉRIE: "
            IsPriorityKeyQualifier = True

Et dans GS1_Resolver

Dim ValidationData As Boolean
Dim primaryKey, keyQualifier, dataAttribute, url As String
'Ajout Ici
Dim priorityKeyQualifier As Variant
Dim index As Integer
priorityKeyQualifier = Array("", "", "")
'fin modif

ValidationData = True 'par défaut on considère que tout est correct
For i = 1 To resultats.Count
    Set unCode = resultats(i)
    LigneHRI = LigneHRI + unCode.Texte
    LigneDecodeData = LigneDecodeData + unCode.Description + vbCrLf
    LigneControlData = LigneControlData + unCode.AdditionalDataInfo
    If unCode.ValidationData = False Then 's'il y a au moins une data incorrecte ça sera signalé
        ValidationData = False
    End If
    
    'Ajout ici
    If unCode.IsPriorityKeyQualifier Then
        Select Case unCode.AI
            Case "22"
                index = 0
            
            Case "10"
                index = 1
                
            Case Else
                index = 2
        End Select
        priorityKeyQualifier(index) = "/" + unCode.AI + "/" + unCode.Code
    End If
    'Fin modifs
    
    If unCode.IsPrimaryKey Then
        If primaryKey <> "" Then
            primaryKey = primaryKey + "/" 'si y'a déjà un primaryKey
        End If
        primaryKey = primaryKey + unCode.AI + "/" + unCode.Code 'construction de la partie d'url qui correspond aux AIs "primaryKey"
    End If
    If unCode.IsKeyQualifier Then
        keyQualifier = keyQualifier + "/" + unCode.AI + "/" + unCode.Code 'construction de la partie d'url qui correspond aux AIs "keyQualifier"
    End If
    If unCode.IsDataAttribute Then
        If dataAttribute <> "" Then
            dataAttribute = dataAttribute + "&" 'si y'a déjà un data attribute
        End If
        dataAttribute = dataAttribute + unCode.AI + "=" + unCode.Code 'construction de la partie d'url qui correspond aux AIs "dataAttribute"
    End If
Next
If ValidationData = False Then
    LigneControlData = vbCrLf + vbCrLf + "ATTENTION, vérifier les données de contrôle !" + vbCrLf + vbCrLf + LigneControlData
End If

'ligne suivante modifiée
url = "https://id.gs1.org/" + primaryKey + priorityKeyQualifier(0) + priorityKeyQualifier(1) + priorityKeyQualifier(2) + keyQualifier

1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
Modifié le 21 janv. 2024 à 21:47

Au début de UnCode

Public IsPriorityKeyQualifier As Interger

'Initialise l'instance de l'objet UnCode
Public Sub Init(TheTag As String, TheCode As String)
    AI = TheTag
    Code = TheCode
    IsPriorityKeyQualifier = 99
End Sub

Dans le select case

        Case "22" 'prio 1
            madescription = "(22) VARIANTE PRODUIT: "
            IsPriorityKeyQualifier = 0
                                  
        Case "10" 'prio 2
            madescription = "(10) N° LOT: "
            IsPriorityKeyQualifier = 1
            
        Case "21" 'prio 3
            madescription = "(21) N° SÉRIE: "
            IsPriorityKeyQualifier = 2

Et dans GS1_Resolver, on remplace le if sur IsPriorityKeyQualifier par

    If unCode.IsPriorityKeyQualifier <> 99 Then
        priorityKeyQualifier(unCode.IsPriorityKeyQualifier) = "/" + unCode.AI + "/" + unCode.Code
    End If

1
NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024 1
22 janv. 2024 à 00:09

Je n'avais pas compris le 99 qui doit être une valeur quelconque, mais différente de celle donnée aux IsPriorityKeyQualifiers.
OK, compris, appliqué et fonctionnel!
Merci

0
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
9 févr. 2024 à 21:45

Je n'ai pas téléchargé ton projet, j'ai fait 2 corrections dans GS1 resolver et je lance par la sub test.

À la fin, j'affiche un message box avec le décodage de chaque essai, j'ai commenté l'interaction avec l'USF que je n'ai pas.

Pour illustrer la question que tu n'as pas comprise, j'ai ajouté un data attribute et j'ai changé l'ordre.

Test + GS1_Resolver

Option Explicit

Sub test()
'ça c'est prévu
GS1_Resolver "(8010)123456ABC(20)12(8011)123456"

'pas ça
GS1_Resolver "(8011)123456(20)12(8010)123456ABC"
End Sub

Function GS1_Resolver(Code As String) As String
Dim fnc1, gs, caracteresOK, pattern, LigneHRI, LigneDecodeData, LigneControlData As String
Dim regex, Match As Object
Dim i As Integer
Dim resultats As Collection
Dim unCode As unCode
Dim boucleOut As Boolean
Dim patterns As New Collection

Set regex = New RegExp

'écriture des patterns unitaires
gs = "(\x1d|\()?" 'quand c'est peut-être
fnc1 = "(\x1d|$|\()" 'quand c'est obligé
caracteresOK = "[\x21\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]"
                 
'Groupe 1
'Balise: 00
'Pattern GS1: ^0(\d{18})$
    patterns.Add "(?:](?:C1|e0|d2|Q3|J1))?\(?(00)\)?(\d{18})" + gs
    
'Groupe [2]
'Balise: 01, 02
'Pattern GS1: ^X(\d{14})$
    patterns.Add "(?:](?:C1|e0|d2|Q3|J1))?\(?(01|02)\)?(\d{14})" + gs
    
'Groupe [3]
'Balise: 10, 21, 22,  243, 254, 420, 710, 711, 712, 713, 714, 715, 4318, 7020, 7021, 7022, 7240, 8002, 8012
'Pattern GS1:  ^X([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,20})$
    patterns.Add "\(?(10|2[12]|243|254|520|71[0-5]|4318|702[0-2]|7240|8002|8012)\)?(" + caracteresOK + "{0,20})" + fnc1
    
'Groupe [4]
'Balise: 20
'Pattern GS1: ^20(\d{2})$
    patterns.Add "\(?(20)\)?(\d{2})" + gs
    
'Groupe [5]
'Balise: 235
'Pattern GS1: ^235([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,28})$
    patterns.Add "\(?(235)\)?(" + caracteresOK + "{0,28})" + fnc1
    
'Groupe [6]
'Balise: 90, 240, 241, 250, 251, 400, 401, 403, 4308, 4319, 7002, 7023, 8004
'Pattern GS1: ^X([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,30})$
    patterns.Add "\(?(90|24[0-1]|25[0-1]|40[013]|4308|7319|7002|7023|8004)\)?(" + caracteresOK + "{0,30})" + fnc1

    
'Groupe [7]
'Balise: 242
'Pattern GS1: ^242(\d{0,6})$
    patterns.Add "\(?(242)\)?(\d{0,6})" + fnc1
    
'Groupe [8]
'Balise: 253
'Pattern GS1:  ^253(\d{13})([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,17})$
    patterns.Add "\(?(253)\)?(\d{13}" + caracteresOK + "{0,17})" + fnc1
    
'Groupe [9]
'Balise: 255
'Pattern GS1: ^255(\d{13})(\d{0,12})$
    patterns.Add "(?:](?:C1|e0|d2|Q3|J1))?\(?(255)\)?(\d{13}\d{0,12})" + fnc1
    
'Groupe [10]
'Balise: 30, 37
'Pattern GS1: ^X(\d{0,8})$
    patterns.Add "\(?(3[07])\)?(\d{0,8})" + fnc1
    
'Groupe [11]
'Balise: 11, 12, 13, 15, 16, 17
'        3100 à 3105, 3110 à 3115, 3120 à 3125, 3130 à 3135, 3140 à 3145, 3150 à 3155, 3160 à 3165,
'        3300 à 3305, 3310 à 3315, 3320 à 3325, 3330 à 3335, 3340 à 3345, 3350 à 3355, 3360 à 3365, 3370 à 3375,
'        3500 à 3505, 3510 à 3515, 3520 à 3525, 3530 à 3535, 3540 à 3545, 3550 à 3555, 3560 à 3565, 3570 à 3575,
'        3200 à 3205, 3210 à 3215, 3220 à 3225, 3230 à 3235, 3240 à 3245, 3250 à 3255, 3260 à 3265, 3270 à 3275, 3280 à 3285, 3290 à 3295,
'        3400 à 3405, 3410 à 3415, 3420 à 3425, 3430 à 3435, 3440 à 3445, 3450 à 3455, 3460 à 3465, 3470 à 3475, 3480 à 3485, 3490 à 3495,
'        3600 à 3605, 3610 à 3615, 3620 à 3625, 3630 à 3635, 3640 à 3645, 3650 à 3655, 3660 à 3665, 3670 à 3675, 3680 à 3685, 3690 à 3695,
'Pattern GS1:^11(\d{6})$
    patterns.Add "\(?(1[123567]|31[0-6][0-5]|3[35][0-7][0-5]|3[246]\d[0-5])\)?(\d{6})" + gs
    
'Groupe [12]
'Balise: 7007
'Pattern GS1:  ^7007(\d{6,12})$
    patterns.Add "\(?(7007)\)?(\d{6,12})" + fnc1
    
'Groupe [13]
'Balise: 7011
'Pattern GS1:  ^7011(\d{6})(\d{0,4})$
    patterns.Add "\(?(7011)\)?(\d{6}\d{0,4})" + fnc1
    
'Groupe [14]
'Balise: 3900 à 3909, 3920 à 3929
'Pattern GS1: ^X(\d{0,15})$
    patterns.Add "\(?(390[0-9]|392[0-9])\)?(\d{0,15})" + fnc1
    
'Groupe [15]
'Balise: 3910 à 3919, 3930 à 3939
'Pattern GS1: ^X(\d{3})(\d{0,15})$
    patterns.Add "\(?(391[0-9]|393[0-9])\)?(\d{3}\d{0,15})" + fnc1
    
'Groupe [16]
'Balise: 3940 à 3943, 8111
'Pattern GS1: ^X(\d{4})$
    patterns.Add "\(?(394[0-3]|8111)\)?(\d{4})" + fnc1
    
'Groupe [17]
'Balise: 3950 à 3959
'Pattern GS1: ^X(\d{0,6})$
    patterns.Add "\(?(395[0-9])\)?(\d{0,6})" + fnc1
    
'Groupe [18]
'Balise: 402
'Pattern GS1: ^402(\d{17})$
    patterns.Add "\(?(402)\)?(\d{17})" + fnc1
    
'Groupe [19]
'Balise: 421
'Pattern GS1:^421(\d{3})([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,9})$
    patterns.Add "(?:](?:C1|e0|d2|Q3|J1))?\(?(421)\)?(\d{3}" + caracteresOK + "{0,9})" + fnc1
    
'Groupe [20]
'Balise: 422, 424, 426
'Pattern GS1:  ^X(\d{3})$
    patterns.Add "\(?(42[246])\)?(\d{3})" + fnc1
    
'Groupe [21]
'Balise: 423, 425
'Pattern GS1: ^X(\d{3})(\d{0,12})$
    patterns.Add "\(?(423|425)\)?(\d{3}\d{0,12})" + fnc1
    
'Groupe [22]
'Balise: 427, 7008
'Pattern GS1:  ^X([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,3})$
    patterns.Add "\(?(427|7008)\)?(" + caracteresOK + "{0,3})" + fnc1
    
'Groupe [23]
'Balise: 4300, 4301, 4310, 4311, 4320
'Pattern GS1:  ^X([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,35})$
    patterns.Add "\(?(430[01]|431[01]|4320)\)?(" + caracteresOK + "{0,35})" + fnc1
    
'Groupe [24]
'Balise: 4302 à 4306, 4312 à 4316, 8110, 8112, 8200
'Pattern GS1: ^X([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,70})$
    patterns.Add "\(?(430[23456]|431[23456]|811[02]|8200)\)?(" + caracteresOK + "{0,70})" + fnc1
    
'Groupe [25]
'Balise: 4307, 4317
'Pattern GS1: ^X([A-Z]{2})$
    patterns.Add "\(?(4307|4317)\)?([A-Z]{2})" + fnc1
    
'Groupe [26]
'Balise: 7230 à 7239
'Pattern GS1: ^X([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{2,30})$
    patterns.Add "\(?(723[0-9])\)?(" + caracteresOK + "{2,30})" + fnc1
    
'Groupe [27]
'Balise: 4309
'Pattern GS1: ^4309(\d{20})$
    patterns.Add "\(?(4309)\)?(\d{20})" + fnc1
    
'Groupe [28]
'Balise: 4321, 4322, 4323
'Pattern GS1: ^X([01])$
    patterns.Add "\(?(432[123])\)?([01])" + fnc1
    
'Groupe [29]
'Balise: 4324, 4325, 7003
'Pattern GS1:  ^X(\d{10})$
    patterns.Add "\(?(432[45]|7003)\)?(\d{10})" + fnc1
    
'Groupe [30]
'Balise: 4326, 7006, 8005
'Pattern GS1: ^X(\d{6})$
    patterns.Add "\(?(4326|7006|8005)\)?(\d{6})" + fnc1
    
'Groupe [31]
'Balise: 7001
'Pattern GS1: ^7001(\d{13})$
    patterns.Add "\(?(7001)\)?(\d{13})" + fnc1
    
'Groupe [32]
'Balise: 7004
'Pattern GS1: ^7004(\d{0,4})$
    patterns.Add "\(?(7004)\)?(\d{0,4})" + fnc1
    
'Groupe [33]
'Balise: 410 à 417
'Pattern GS1: ^X(\d{13})$
    patterns.Add "\(?(41[0-7])\)?(\d{13})" + gs
    
'Groupe [34]
'Balise: 7005
'Pattern GS1: ^7005([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,12})$
    patterns.Add "\(?(7005)\)?(" + caracteresOK + "{0,12})" + fnc1
    
'Groupe [35]
'Balise: 8006, 8026
'Pattern GS1: ^X(\d{14})(\d{2})(\d{2})$
    patterns.Add "(?:](?:C1|e0|d2|Q3|J1))?\(?(8006|8026)\)?(\d{14}\d{2}\d{2})" + fnc1
    'patterns.Add "(?:](?:C1|e0|d2|Q3|J1))?\(?(8006|8026)\)?(\d{14})(\d{2})(\d{2})" + fnc1
    
'Groupe [36]
'Balise: 8007
'Pattern GS1: ^8007([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,34})$
    patterns.Add "\(?(8007)\)?(" + caracteresOK + "{0,34})" + fnc1
    
'Groupe [37]
'Balise: 8008
'Pattern GS1: ^8008(\d{8})(\d{0,4})$
    patterns.Add "\(?(8007)\)?(\d{8}\d{0,4})" + fnc1
    
'Groupe [38]
'Balise: 8009
'Pattern GS1: ^8009([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,50})$
    patterns.Add "\(?(8009)\)?(" + caracteresOK + "{0,50})" + fnc1
    
'Groupe [39]
'Balise: 8010
'Pattern GS1:  ^8010([\x23\x2D\x2F\x30-\x39\x41-\x5A]{5,30})$
    patterns.Add "\(?(8010)\)?([\x23\x2D\x2F\x30-\x39\x41-\x5A]{5,30})" + fnc1
    
'Groupe [40]
'Balise: 7009
'Pattern GS1: ^7009([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,10})$
    patterns.Add "\(?(7009)\)?(" + caracteresOK + "{0,10})" + fnc1
    
'Groupe [41]
'Balise: 7010
'Pattern GS1: ^7010([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,2})$
    patterns.Add "\(?(7010)\)?(" + caracteresOK + "{0,2})" + fnc1
    
'Groupe [42]
'Balise: 7040
'Pattern GS1: ^7040(\d[\x21-\x22\x25-\x2F\x30-\x39\x41-\x5A\x5F\x61-\x7A]{3})$
    patterns.Add "\(?(7040)\)?(\d[\x21\x22\x25-\x2F\x30-\x39\x41-\x5A\x5F\x61-\x7A]{3})" + fnc1
    
'Groupe [43]
'Balise: 8011
'Pattern GS1: ^8011(\d{0,12})$
    patterns.Add "\(?(8011)\)?(\d{0,12})" + fnc1
    
'Groupe [44]
'Balise:  7030 à 7039
'Pattern GS1: ^X(\d{3})([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,27})$
    patterns.Add "\(?(703[0-9])\)?(\d{3}" + caracteresOK + "{0,27})" + fnc1

'Groupe [45]
'Balise: 8001
'Pattern GS1: ^8001(\d{14})$
    patterns.Add "\(?(8001)\)?(\d{14})" + fnc1
    
'Groupe [46]
'Balise: 8003
'Pattern GS1: ^8003(\d{14})([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,16})$
    patterns.Add "\(?(8003)\)?(\d{14}" + caracteresOK + "{0,16})" + fnc1
   
'Groupe [47]
'Balise: 8013, 8020
'Pattern GS1: ^X([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,25})$
    patterns.Add "(?:](?:C1|e0|d2|Q3|J1))?\(?(8013|8020)\)?(" + caracteresOK + "{0,25})" + fnc1
    
'Groupe [48]
'Balise: 8017, 8018
'Pattern GS1: ^X(\d{18})$
    patterns.Add "\(?(801[78])\)?(\d{18})" + fnc1
    
'Groupe [50]
'Balise: 91 à 99
'Pattern GS1: ^X([\x21-\x22\x25-\x2F\x30-\x39\x3A-\x3F\x41-\x5A\x5F\x61-\x7A]{0,90})$
    patterns.Add "\(?(9[1-9])\)?(" + caracteresOK + "{0,90})" + fnc1

'valeur par défaut si la regex ne matche pas
LigneHRI = "Code incorrect"
LigneDecodeData = ""
LigneControlData = ""
Set resultats = New Collection

Do
    boucleOut = False
    For Each pattern In patterns
        'on teste chaque pattern pour le début du code
        regex.pattern = "^" + pattern
        If (regex.test(Code)) Then
            boucleOut = True
            LigneHRI = ""
            'si ça marche, on extrait la partie
            Set Match = regex.Execute(Code)(0)
    
            Set unCode = New unCode
            unCode.Init Match.SubMatches(0), Match.SubMatches(1)
            resultats.Add unCode
            
            'on enlève ce qu'on vient de traiter
            Code = Replace(Code, Match.Value, "")
            
            'et on recommence
            Exit For
        End If
    Next
    
Loop While Len(Code) > 0 And boucleOut 'si boucleOut vaut false c'est qu'on vient de faire un tour complet et qu'on est sur un cas imprévu

If boucleOut = False Then
    LigneHRI = "Erreur data imprévue !" ' + vbCrLf
End If

Dim ValidationData As Boolean
Dim primaryKey, keyQualifier, dataAttribute, url As String
Dim priorityKeyQualifier As Variant
Dim index As Integer
priorityKeyQualifier = Array("", "", "")
'ajout ici --------------------
Dim previousPrimaryKeys
Set previousPrimaryKeys = CreateObject("Scripting.Dictionary")
'fin modif -------------------

ValidationData = True 'par défaut on considère que tout est correct
For i = 1 To resultats.Count
    Set unCode = resultats(i)
    LigneHRI = LigneHRI + unCode.Texte
    LigneDecodeData = LigneDecodeData + unCode.Description + vbCrLf
    LigneControlData = LigneControlData + unCode.AdditionalDataInfo
    If unCode.ValidationData = False Then 's'il y a au moins une data incorrecte ça sera signalé
        ValidationData = False
    End If
    
    If unCode.IsPriorityKeyQualifier <> 99 Then
        priorityKeyQualifier(unCode.IsPriorityKeyQualifier) = "/" + unCode.AI + "/" + unCode.Code
    End If
    
    If unCode.IsPrimaryKey Then
        If primaryKey <> "" Then
            primaryKey = primaryKey + "/" 'si y'a déjà un primaryKey
        End If
        primaryKey = primaryKey + unCode.AI + "/" + unCode.Code 'construction de la partie d'url qui correspond aux AIs "primaryKey"
        'ajout ici--------------------------
        previousPrimaryKeys.Add unCode.AI, 1
    End If
    
    If unCode.IsPotentialyKeyQualifier.Count > 0 Then
        'valeurs par défaut
        unCode.IsKeyQualifier = False
        unCode.IsDataAttribute = True
        Dim pKey
        For Each pKey In unCode.IsPotentialyKeyQualifier
            If previousPrimaryKeys.Exists(pKey) Then
                'si le primaryKey est déjà présent (j'ai pas géré le cas où il arriverait plus loin dans le code barre, est-ce possible?
                unCode.IsKeyQualifier = True
                unCode.IsDataAttribute = False
            End If
        Next
    End If
    'fin modifs-----------------------------------
            
    If unCode.IsKeyQualifier Then
        keyQualifier = keyQualifier + "/" + unCode.AI + "/" + unCode.Code 'construction de la partie d'url qui correspond aux AIs "keyQualifier"
    End If
    If unCode.IsDataAttribute Then
        If dataAttribute <> "" Then
            dataAttribute = dataAttribute + "&" 'si y'a déjà un data attribute
        End If
        dataAttribute = dataAttribute + unCode.AI + "=" + unCode.Code 'construction de la partie d'url qui correspond aux AIs "dataAttribute"
    End If
Next
If ValidationData = False Then
    LigneControlData = vbCrLf + vbCrLf + "ATTENTION, vérifier les données de contrôle !" + vbCrLf + vbCrLf + LigneControlData
End If

'ligne suivante modifiée
url = "https://id.gs1.org/" + primaryKey + priorityKeyQualifier(0) + priorityKeyQualifier(1) + priorityKeyQualifier(2) + keyQualifier
If dataAttribute <> "" Then 'Si pas de dataAttribute
    url = url + "?" + dataAttribute
End If


'UserForm1.TextBox_Code_HRI = LigneHRI
'UserForm1.TextBox_All_Data = LigneDecodeData
'UserForm1.TextBox_Data_Controle = LigneControlData
'UserForm1.TextBox_Digital_Link_URI = url

MsgBox url

End Function

J'ai pas touché à UnCode


1
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
Modifié le 9 févr. 2024 à 21:46

PS, depuis le temps qu'on y est, tu aurais largement pu apprendre les bases Python, et on aurait fait un truc 1000 fois plus simple et efficace…

Et je dis ça alors que je n'aime pas Python

0
NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024 1 > Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024
10 févr. 2024 à 02:01

Pour Python, si je ne me trompe pas, l'installation a minima d'un interpréteur est nécessaire.

Comme évoqué dans l'un de nos échanges, je ne suis pas administrateur des postes qui utilisent ce projet, notre DSI n'est pas ouverte du tous à ce genre de programme qui permet d'exécuter du code.

Excel est présent sur tous nos postes et heureusement que nos différents secrétariats utilisent des macros depuis très longtemps, car ils avaient envisagé de bloquer VBA a une époque.

Entre nous, quel défi de gérer cela en VBA! Je trouve le jeu même très sympathique.

Pour revenir au code:

C'est OK avec tes dernières modifications, merci beaucoup.

Pour ton exemple et la question que je n'avais pas comprise:
Si je l'ai bien comprise, le cas évoqué ne devrait pas arriver car les codes-barres respectent l'ordre suivant:
primaryKey(s) suivit de keyQualifier(s) et fini par dataAttribute(s)

Pour la suite je peux porter la même chose sur les autres keyQualifiers, mais pour les 3 qui ont un ordre "IsPriorityKeyQualifier" comment dois-je gérer?

0
NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024 1 > NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024
10 févr. 2024 à 20:02

Finalement, on peut mettre un ordre sur tous les AIs:
-
primaryKeys dans l'ordre:
01, 8006, 8013, 8010, 414, 415, 417, 8017, 8018, 255, 00, 253, 401, 402, 8003 et 8004.
-
keyQualifiers dans l'ordre:
22, 10, 21, 8011, 254, 8020, 8019, 235 et 7040.
-
dataAttributes dans l'ordre:
J'ai identifié l'ordre, il correspond au regroupement fait dans le select case du module de classe unCode.
Exemple:
Ordre N° 1 => les AIs: 3100 à 3105, 3200 à 3205, 3560 à 3565 et 3570 à 3575
Ordre N° 2 => les AIs: 3110 à 3115, 3210 à 3215, 3220 à 3225 et 3230 à 3235


Ordre N° 10 => AI: 02
Ordre N° 11 => AI: 11


Sachant que dans un code-barres il ne peut avoir des AIs d'un même groupe, soit:
Si dans un code-barres l'AI 3100 est présent les AIs 3101 à 3105 ne pourrons pas l'être.
Cela peut nous simplifier les choses non?

0
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656 > NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024
10 févr. 2024 à 20:12

Bonsoir

Pour Python, si je ne me trompe pas, l'installation a minima d'un interpréteur est nécessaire.

Comme évoqué dans l'un de nos échanges, je ne suis pas administrateur des postes qui utilisent ce projet, notre DSI n'est pas ouverte du tous à ce genre de programme qui permet d'exécuter du code.

Il y a Thonny qui fonctionne sans installation https://thonny.org/

Entre nous, quel défi de gérer cela en VBA! Je trouve le jeu même très sympathique.

 Facile d'écrire ça quand c'est souvent moi qui me bats avec les faiblesses de VBA ;)

0
NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024 1 > Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024
12 févr. 2024 à 13:59

Citation: Facile d'écrire ça quand c'est souvent moi qui me bats avec les faiblesses de VBA ;)
De la manière ou j'ai tourné ma phrase, je tends le bâton pour me faire battre!
Je sous entendais plus le fait que tu relèves à chaque fois les défis liés à un langage très limité par rapport aux langages de programmations récents! Tes exemples et explications rendent pour moi le travail bien plus sympathique.
-
Pour revenir à Python cela semble mal partie, notre DSI bloque les exécutables et elle ne semble pas décidée à nous autoriser celui-ci! Et nous invite chercher une application existante ou à demander une prestation!

0
NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024 1
11 oct. 2023 à 21:46

Bonsoir,
Effectivement ce qui compte ce sont les caractères entre 10 et AR!
J'essaie de jouer avec (.+?) mais je sèche toujours !

0
NeriXs Messages postés 258 Date d'inscription lundi 4 mai 2015 Statut Membre Dernière intervention 27 février 2024 1
Modifié le 11 oct. 2023 à 22:23


Il y a quelque chose qui m'échappe !


85(\d{14})36(\d{6})10(?<=10).{1,20}(?=AR)29(\d{6})15(PC\d+)$

85339147802789523626847310205970239AR2950793415PC7098624031

https://regex101.com/r/n8MPCT/1

0
Whismeril Messages postés 19026 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 20 avril 2024 656
11 oct. 2023 à 22:35

Cette instruction

(?<=10)

veut dire que 10 doit être avant la capture mais pas en faire partie.

Du coup, tu ne peux pas la mettre au milieu d'un pattern, idem pour (?=AR) qui signifie après la capture.


0
Rejoignez-nous