C'est surtout que le défi était très interressant : des formats de dates et de saisie de date très divers, avec obligation de récupérer la plus petite et la plus grandeC'est très instructif mais ça vole haut !
Si je l'utilise car cela me permet de vérifier dans la fenêtre des variables locales si la chaîne retourne un motif valide.Si je me trompe tu n'utilises pas Resultat, non ?
With CreateObject("vbscript.regexp")
.....
End With
me permet d'accéder à des infos qui me permettent de comprendre les erreurs et d'arriver à mes fins.Set oRegExp = CreateObject("vbscript.regexp")
With oRegExp
.Pattern = "^(0[1-9]|[12]\d|3[01])/(01|0[3-9]|1[012])/(190[1-9]|19[1-9]\d|(20|21)\d\d)|(0[1-9]|[1]\d|[2][0-8])/02/(190[1-9]|19[1-9]\d|(20|21)\d\d)|29/02/((190|210)[48]|(19|20|21)([13579][26]|[2468][048])|200[048])$"
.Global = True
'Set Resultat = .Execute(MaChaine)
If .test(MaChaine) = True Then DateValide = True Else DateValide = False
End With
Tu sais bien ce que j'en pense puisque nous en avons discutéEt malgré mon appel, je n'ai pas vu de formulistes essayer de s'y confronter ...
Mais je pense que ça peut te donner des idées ...
"29/02/((190|210)[48]|(19|20|21)([13579][26]|[2468][048])|200[048])"
Depuis l'ajustement du calendrier grégorien, sont bissextiles les années :
1) soit divisibles par 4 mais non divisibles par 100
2) soit divisibles par 400.
L'utilisation du "|" ="ou" et l'utilisation des parenthèses ( ) te permet de créer des masques.(190|210)[48]|(19|20|21)([13579][26]|[2468][048])
, littéralement pour les années débutant par 190 ou ("|") 210, les années bissextiles se terminent par 4 ou 8 ([48], les crochets "[ ]" délimitent une classe de caractères).(190|210)[48]
dont les 2 1er chiffres sont soit 19, soit 20 soit 21(19|20|21)([13579][26]
. Le 3ème chiffres ne peut être que impaire, donc l'un de ceux compris dans la classe(19|20|21)
et le 4ème 2 ou 6([13579]
(exemple des années bissextiles dans les décennies impaires : 1912 et 1916, 1932 et 1936,...)
Si la décennie de ces siècles est paire, le dernier chiffre sera obligatoirement 0, 4 et 8, et si la décennie est impaire, 2 et 6 (utilisation de "|" pour distinguer les 2 cas au sein du même masque délimité par un jeu de parenthèses).(19|20|21)
([13579][26]|[2468][048])
(19|20|21)([13579][26]|[2468][048])
200[048]
Euh, j'ai pas tout testéJean-Noël, si tu as quelque chose à ajouter ou si j'ai dis une bêtise, ne te gène pas pour intervenir.
OK.Au suivant
(0[1-9]|[1]\d|[2][0-8])/02/(190[1-9]|19[1-9]\d|(20|21)\d\d)
Donc 3 possibilités délimitées par le "|" (ou) enfermé dans un jeu de parenthèses (le masque) : les jours peuvent aller :((0[1-9]|[1]\d|[2][0-8])|[1]\d|[2][0-8])
donc littéralement la syntaxe comporte un 0 suivi de l'un des chiffres de la classe 1 à 90[1-9]
, donc le chiffres commence automatiquement par 1 et est suivi d'un autre chiffre compris entre 0 (10) et 9 (19). Tu remarqueras que contrairement à la partie 01-09 où le 2ème chiffre ne peut pas être 0, là le 0 fait partie de cette classe, d'où l'utilisation du \d (barre oblique suivie d'un digit (nombre allant de 0 à 9).[1]\d
.[2][0-8]
(à noter que j'aurai pu (dû ?) l'écrire
, \/ voulant dire "le caractère /"
Créons un masque pour gérer les alternatives des siècles (toujours le même principe : des "|" séparant les différentes alternatives, le tout isolé par un jeu de parenthèses) :(190[1-9]|19[1-9]\d|(20|21)\d\d)
(190[1-9]|19[1-9]\d|(20|21)....)
(de 1901 à 1909)190[1-9]
, littéralement, le siècle19[1-9]
suivi de la décennie allant de1910 à 1990, donc
.[1-9]
.
suivi de 2 digits pour les 2 derniers chiffres(20|21)
que j'aurais pu également écrire
ou encore[0-9][0-9]
NB : les accolades permettent de délimiter des intervalles de reconnaissance. Ces intervalles sont sont placés derrière le caractère à traités (ils sont dits "postfixés").\d{2}
Tu peux également te référer au fichier produit par Jean-Noël qui t'explique la syntaxe d'une expression rationnelle.{n} signifie "exactement n occurrences"
Exemple : Le motif "a{3}" permet de décrire la chaîne "aaa", et rien d'autre !
{n, p} signifie "entre n et p occurrences"
Exemple : Le motif "a{1, 3}" permet de décrire les chaînes "a", "aa" et "aaa"
{n,} signifie "au moins n occurrences"
Exemple : Le motif "a{5,}" permet de décrire les chaînes "aaaaa", "aaaaaa", "aaaaaaa", etc...
# Observation pour conclure :
Ici aussi, les intervalles de reconnaissance sont postfixés.
Remarque bien que je place ces 2 digits après la parenthèse fermante du masque gérant les siècles
car ces 2 siècles sont concernées par ce cas de figure.(20|21)\d\d
auquel je rajoute le jeu de parenthèses entrante et sortante du masque permettant la gestion des alternatives de la partie "année" de ce motif.190[1-9]|19[1-9]\d|(20|21)\d\d
(190[1-9]|19[1-9]\d|(20|21)\d\d)
C'est pas évident, il faudrait faire des tests, mais si j'avais bien compris ce que j'avais lu, il faut être prudent avec le | car en gros, s'il a trouvé la partie gauche, il ne cherche plus la partie droite pour cette occurence (comme un test "si" qui n'analyse pas la suite une fois la condition remplie), ce qui en général ne pose pas de problème, mais peux en poser dans certains cas particuliersJNP
Tu pourrais développer ton..., stp.
Le slash n'est pas un caractère syntaxique (donc interdit) dans RegExp, donc il ne nécessite pas de \ devantOn place ensuite la barre permettant de séparer les jours du mois (à noter que j'aurai pu (dû ?) l'écrire , \/ voulant dire "le caractère /"
"(0[1-9]|[12]\d|3[01])/(01|0[3-9]|1[012])/(190[1-9]|19[1-9]\d|(20|21)\d\d)"
Le masque distingue donc 3 cas :(01|0[3-9]|1[012])
- de février à septembre
et les 3 derniers0[3-9]
.1[012]
Via mon clavier, c'est juste à côté( et puis de toutes les façons, Jean-Noeln'est jamais bien loin).
ben que même si j'ai été pas mal loin, je ne suis pas arrivé au bout, alors si on commençait par celui-làCela vous intéresserai toi ,JNP, (moioui) , autrui de compléter ce qu'avait JNP en faisant un grand meltingpot des patterns des plus simples au plus extravagants.
...
Qu'en pensez-vous ?
Bonne soiréeRe,C'est surtout que le défi était très interressant : des formats de dates et de saisie de date très divers, avec obligation de récupérer la plus petite et la plus grande ...
Cela vous intéresserai toi ,JNP, (moioui) , autrui de compléter ce qu'avait JNP en faisant un grand meltingpot des patterns des plus simples au plus extravagants.
On pourrait catégoriser la chose: Dates/Emaills/Adresses/Alphanumériques/Patronymes/ etc...
Qu'en pensez-vous ?
ben que même si j'ai été pas mal loin, je ne suis pas arrivé au bout, alors si on commençait par celui-là ... :
Envoyé par JNP
Re ,C'est surtout que le défi était très interressant : des formats de dates et de saisie de date très divers, avec obligation de récupérer la plus petite et la plus grande ...
Function testDate(Cellule As Range) As String
'Application.Volatile
Dim oRexp, Match, Matches, MaDate As Date, MesMois, MesMoisBis, I As Integer, MaChaine As String, Jour As Long, An As Long
If Cellule = "" Then Exit Function
MesMois = Array("janvier", "janv.", "janv", "février", "févr.", "févr", "mars", "avril", "avr.", " avr ", "mai", "juin", _
"juillet", "juil.", "juil", "août", "septembre", "sept.", "sept", "octobre", "oct.", "oct", "novembre", "nov.", "nov", "décembre", "déc.", "déc")
MesMoisBis = Array("/01/", "/01/", "/01/", "/02/", "/02/", "/02/", "/03/", "/04/", "/04/", "/04/", "/05/", "/06/", "/07/", "/07/", "/07/", _
"/08/", "/09/", "/09/", "/09/", "/10/", "/10/", "/10/", "/11/", "/11/", "/11/", "/12/", "/12/", "/12/")
MaChaine = Cellule.Value
For I = LBound(MesMois) To UBound(MesMois)
If InStr(1, Cellule.Value, MesMois(I), vbTextCompare) > 0 Then
MaChaine = Trim(Replace(MaChaine, MesMois(I), MesMoisBis(I)))
MaChaine = Replace(MaChaine, " /", "/")
MaChaine = Replace(MaChaine, "/ ", "/")
Exit For
End If
Next I
Set oRexp = CreateObject("vbscript.regexp")
With oRexp
.Global = True
.Pattern = "(\b\d{1})(/\d{2}/\d{4})"
Set Matches = .Execute(MaChaine)
MaChaine = .Replace(MaChaine, "0$1$2")
.Pattern = "(\b\s)(\d{1})(/\d{2}/)((?:0|1|2)[0-9])"
Set Matches = .Execute(MaChaine)
MaChaine = .Replace(MaChaine, "0$2$320$4")
.Pattern = "(\b\s)(\d{1})(/\d{2}/)((?:3|4|5|6|7|8|9)[0-9])"
Set Matches = .Execute(MaChaine)
MaChaine = .Replace(MaChaine, "$10$2$319$4")
End With
With oRexp
.Pattern = "((0[1-9]|[12]\d|3[01])/(0[13578]|1[02])|(0[1-9]|[12]\d|30)/(0[469]|11))/(190[1-9]|19[1-9]\d|(20|21)\d\d)|(0[1-9]|[1]\d|[2][0-8])/02/(190[1-9]|19[1-9]\d|(20|21)\d\d)|29/02/((190|210)[48]|(19|20|21)([13579][26]|[2468][048])|200[048])"
.Global = True
Set Matches = .Execute(MaChaine)
If .test(MaChaine) = True Then testDate = CDate(Right(MaChaine, 10)) Else testDate = "Date non valide"
End With
End Function