Expressions régulières - Patterns pour RegExp

JNP

XLDnaute Barbatruc
Pour les passionnés de RexExp et petit défi

Bonjour le fil :),

Pour les rares passionnés de ce club où je me sens souvent seul :p...

Un petit fil sur comment modifier à la volée une String facilement ;).

Un autre fil pour découper les chaines trop longues dans une cellule :).

Mais surtout, et c'est là qu'est le petit défi, un fil toujours en cours où j'ai du mal à imaginer une solution par formule ou par VBA sans RegExp, mais je sais que les pointures vont bien me prouver que je manque d'imagination :p...

Bonne journée à toutes et à tous :cool:
 

Odesta

XLDnaute Impliqué
Re : Expressions régulières - Patterns pour RegExp

Bonjour
Ayant quelques heures devant moi, je parcour le forum à l'affut de deux ou trois trucs à glanner (apprendre et toujours apprendre) et je tombe sur le fil des ExpReg. Ni une ni deux, je me dis : j'avais regardé et laissé tombé, je m'y remets et je comprends.
Le fichier de récap de JNp est très explicite. Alors, j'utilise, je m'amuse, et j'explore. Le /ooo notamment....
(SVP, pour une raison de taille de fichier, je n'ai pas étendue les formules)

Super travail JNP
Je continue à apprendre !
A plus tard

Olivier
 

Pièces jointes

  • Jouons_avec_les_Octales.xls
    65.5 KB · Affichages: 123

JNP

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Re :),
Super travail JNP
Merci Olivier, ça me fait plaisir de voir que ça intérresse quelqu'un d'autre que Jean-Marie et moi :p
Je sais pas si tu as vu, mais finalement, personne n'est venu relever le petit défi :rolleyes:...
A savoir : avec ou sans VBA, la recherche Word accepte aussi (cocher Caractères génériques) les masques RegExp (avec quelques subtilités de Word)...
Bon WE :cool:
 

david84

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Bonsoir,
ci-joint une proposition de motif d'expression rationnelle permettant de tester la validité d'une date entrée au format date
.

Le but est de tester la validité d'une date comprise entre le 01/01/1901 et le 31/12/2199, y compris bien entendu les années bissextiles.

Le motif étant complexe, j'ai volontairement cherché à "simplifier" entre distinguant 3 sous-motifs :
- gestion des mois de l'année mis à part février
- gestion des 28 jours du mois de février
- gestion du 29 février des années bissextiles.

On peut certainement imbriquer certaines parties mais on risque de perdre en lisibilité : ceci-dit, je vous encourage à le faire une fois les sous-motifs analysés afin de vous entraîner à la création des motifs.

La partie traitement de la fonction peut elle aussi sûrement être simplifiée.

Code:
Function DateValide(MaChaine As String) As Boolean
Dim oRegExp, Resultat, k, Item
  'Application.Volatile 'recalcul automatique
  Set oRegExp = CreateObject("vbscript.regexp")
  
  'oRegExp.Pattern = "29/02/((190|210)[48]|(19|20|21)([13579][26]|[2468][048])|200[048])" 'test 29/02
  'oRegExp.Pattern = "(0[1-9]|[1]\d|[2][0-8])/02/(190[1-9]|19[1-9]\d|(20|21)\d\d)" 'test février
  '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)"'autres jours
  
  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])"
  
  oRegExp.Global = True
  Set Resultat = oRegExp.Execute(MaChaine)
    For k = 0 To Resultat.Count - 1
        Set Item = Resultat.Item(k)
    Next
  If Item = MaChaine Then DateValide = True Else DateValide = False
  
Set oRegExp = Nothing
Set Resultat = Nothing
Set Item = Nothing

End Function

Je vous ai placé un fichier dans lequel vous pouvez procéder aux tests.
Merci de me faire remonter les éventuels bugs, remarques, etc.
A+
 

Pièces jointes

  • RegExp_date_valide.xls
    104 KB · Affichages: 75

Staple1600

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Bonsoir le fil


David84
Ça c'est du pattern de derrière les fagots (lol)

C'est du creuse-méninges comme je les aime.

Bien que comme toi, je suppute qu'on puisse rafraichir le pattern, surtout aux niveau de la frange. ;)

Rien que pour le plaisir, tu permets de t'offrir une paire d'endives ;)
Code:
Function DateValide(MaChaine As String) As Boolean
Dim  Resultat, k, Item
  'Application.Volatile 'recalcul automatique
With CreateObject("vbscript.regexp")
  .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)
    For k = 0 To Resultat.Count - 1
        Set Item = Resultat.Item(k)
    Next
End With
  If Item = MaChaine Then DateValide = True Else DateValide = False
Set Resultat = Nothing
Set Item = Nothing
End Function

Quoique tu l'as déjà un peu plus court que celui de David Lauener ;)
Code:
"(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$"
 
Dernière édition:

david84

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Merci JM:) et merci pour les endives;),
teste de ton côté quand tu as le temps et dis-moi ce que cela donne.
Comme je l'ai dit dans mon message précédent, l'intérêt n'est pas tant la fonction que le motif en lui-même dont l'intérêt est de pouvoir être réutilisé dans d'autres circonstances.
Sur ce, bonne nuit et à +:cool:
 

Staple1600

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Re


Les patterns je viens d'en voir défiler 7 pages dans ma bible regexpienne (voir mon édition de mon précédent message)

Et d'après ce que je peux lire* soit on peut raccourcir le pattern en rallongeant la fonction comme ci-dessous
(attention ce n'est point du vba ;), mais y a du pattern inside ;)

PHP:
sub isvaliddate {
  my $input = shift;
  if ($input =~ m!^((?:19|20)\d\d)[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$!) {
    # At this point, $1 holds the year, $2 the month and $3 the day of the date entered
    if ($3 == 31 and ($2 == 4 or $2 == 6 or $2 == 9 or $2 == 11)) {
      return 0; # 31st of a month with 30 days
    } elsif ($3 >= 30 and $2 == 2) {
      return 0; # February 30th or 31st
    } elsif ($2 == 2 and $3 == 29 and not ($1 % 4 == 0 and ($1 % 100 != 0 or $1 % 400 == 0))) {
      return 0; # February 29th outside a leap year
    } else {
      return 1; # Valid date
    }
  } else {
    return 0; # Not a date
  }
}
source

*: là c'est pas ma bible, mais mon almanach regexpien du jeudi ;)

PS: Apparemment les David sont génétiquement prédisposés au pattern. ;)
 
Dernière édition:

david84

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Re JM,
tout d'abord, merci pour ton lien que j'ai stocké afin de l'étudier à tête reposée.
Les recherches que j'avais menées avant de me coltiner le motif n'avaient rien donné de concluant (sinon, je ne me serais pas "farci" le travail:confused:).
Je l'ai rapidement parcouru et je le rejoins sur une idée que j'avais en tête mais que je n'ai pas voulu aborder dans un 1er temps (j'ai préféré me cantonner à l'élaboration strict du motif et attendre les retours) : la possibilité de diversifier la liste des séparateurs ( espace, -,...), ce qui serait utile pour retrouver des dates dans un texte saisi ou recopié dans Excel.

On pourrait également rajouter le fait de rechercher :
- la possibilité de rechercher au format de date mm/dd/yyyy (inversion de certaines parties du motif) comme il l'a lui-même relevé
- d'autres formats de type jj/mm/aa par exemple,
mais là c'est plutôt à l'utilisateur de procéder à une adaptation du motif en fonction de la spécificité de sa problématique.

Je remarque également que son motif comme le mien sont formatés pour les dates commençant le 01/01/1901 (la plage du mien allant jusqu'au 31/12/2199 contre 31/12/2099 pour le sien, mais dans le seul but d'inclure l'année 2100 qui n'est pas bissextile dans le calendrier Grégorien, sinon pas d'intérêt) : les années antérieures à 1901 peuvent bien sûr être traitées par RegExp mais le problème réside dans le traitement de ces dates par Excel:mad: (décalage d'une journée pour le début de l'année 1900 et pour les années antérieures c'est pire !).

Il faudrait peut-être faire un test en utilisant le calendrier 1904 pour voir si cela change quelque chose au traitement des années 1900 et inférieures.

Concernant le raccourcissement éventuel du motif, on peut bien sûr voir ce qu'il y a lieu de faire mais je voulais dans un 1er temps présenter un motif aussi clair que possible (la recherche d'un motif raccourci peut entraîner une dégradation de la compréhension du motif).
Une fois cela effectué, on peut bien sûr tester d'autres versions en sachant que l'on peut si besoin revenir à la structure d'origine car si le motif n'est pas clair (puisque plus abstrait), c'est plus compliqué de l'étudier en cas de recherche d'erreur.

Je regarderai ton pattern non VBA:rolleyes: pour tenter de le comprendre.

PS: Apparemment les David sont génétiquement prédisposés au pattern.
pas plus que les Jean-XXX;) !
A+

Edit : en fait, j'ai dis une c..... : son motif prend en compte l'année 1900. Je regarderai si les résultats concordent avec les dates réelles de cette année-là ou pas.
 
Dernière édition:

Staple1600

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Bonjour à tous


david84:
Quand je vois deux David (car vous êtes au moins deux à faire dans le motif) qui font dans le pattern d’élevage en plein air, je me dis qu'il y a un rocher sur l'anguille. ;)

et si on mixait la fonction RegExp avec ce bon vieux VBA pour nous simplifier la tâche ?
La fonction IsDate renvoie la valeur True si l'expression est une date ou peut être reconnue en tant que date ; sinon elle renvoie la valeur False. Dans Microsoft Windows, la plage des dates valides s'étend du 1er janvier 100 au 31 décembre 9999. Les plages varient en fonction des systèmes d'exploitation.
 
Dernière édition:

david84

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Re JM,
et si on mixait la fonction RegExp avec ce bon vieux VBA pour nous simplifier la tâche ?

Sur le principe, pourquoi pas ? J'ai testé dernièrement un "mixte" RegExp avec un algorithme que j'ai traduit en VBA pour tester la validité d'un n°SIRET et cela fonctionne bien. Cela permet à la comptable du service d'éviter les fautes de frappe lorsque qu'elle saisit le SIRET dans un dossier.

Le principe :
- la chaîne de caractères est d'abord confrontée à un motif RegExp pour tester la validité syntaxique (le n° a bien 14 chiffres, tous les chiffres entre 0 et 9, sauf le 13ème entre 1 et 9 (le 1er chiffre peut faire l'objet d'une plage de nombre plus restreint en fonction de l'orientation que l'on veut donner à la recherche),...
- dans un 2ème temps, une adaptation VBA de l'algorithme de LHUN permet de tester la validité des clés du SIREN et du SIRET.
Si les 2 étapes sont ok, le SIRET est considéré comme valide.

Le problème dans le cas qui nous occupe est que je ne vois pas trop ce que IsDate apporterait au traitement...
Teste :
Code:
Sub test()
If IsDate(ActiveCell.Value) Then MsgBox "date" Else MsgBox "non"
End Sub
Tu verras que le code te ramène comme correcte une date telle que 12/31/2000 (logique) alors que le motif te le refuse.
Mais ceci-dit, il y a sûrement à creuser de ce côté-là ou ailleurs.
Si tu as une idée particulière en tête, n'hésite pas:cool:.
A+
 

david84

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Re JM
quelques infos suite à quelques tests :
Le motif de David Lauener qui prend en compte l'année 1900 donne des résultats erronés :
- le 01/01/1900 ramène une date non valide
- le 29/01/1900 ramène une date valide alors que 1900 n'est pas une années bissextile.

Ceci-dit, gardons bien 2 choses en tête :
- ce n'est pas le motif qui est faux mais bien Excel qui fausse les résultats
- les tests sont faits sur des dates.

Or, ce test n'est pas le meilleur moyen pour tester les résultats du motif.
En effet, à mon sens, le test le plus pertinent est à faire sur des chaînes de caractères, par exemple des données de généalogie retranscrites dans Excel où le but est d'extraire les dates de naissance et de décès de personnes. Sur ce type d'exemple, c'est une chaîne de caractères répondant au pattern qui est recherchée et non une date.

Je n'ai pas testé mais je pense que là, le RegExp pourra vraiment être utile et ne sera pas faussé par le mode de traitement d'Excel concernant les dates.

Nous devrions ainsi pouvoir extraire des chaînes de caractères de type "18/06/1815" qui, en tant que date n'existent pas dans Excel.

Si c'est le cas, il n'y aurait alors aucun frein à l'extension du motif permettant la recherche de chaînes de caractères s'apparentant à des dates valides de siècles antérieurs au 20ème.

Concernant le test effectué avec le calendrier 1904, il empêche le traitement des années antérieures à ...1904:eek:.

Dernière chose : j'ai regardé le mode de traitement proposé sur le lien que tu m'as communiqué et ce que j'en ai compris me conforte dans ce que je pense : la chaîne de caractère est en 1er lieu soumise au filtre syntaxique du motif (la forme) et ce n'est qu'ensuite que la procédure traite le fond (comme dans l'exemple de traitement de la validité du SIRET).

Même si c'est l'ensemble du code qu'il faut alors prendre en compte et non plus uniquement le motif, cette solution présente plusieurs avantages :
- un motif générique, et donc plus simple à élaborer et à comprendre
- une procédure de traitement prenant en compte tous les cas de figure et allégeant l'utilisateur des possibles ré actualisations du motif (dans le motif fourni, les dates telles que le 29/01/2400 n'est pas traitée ce qui obligera ta lointaine descendance à retoucher le pattern que tu auras précieusement gardé (tu vois la galère;)) !
A+
 

JNP

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Re :),
Comme il y a beaucoup de lien sur ce fil, j'espère que tu as désossé le petit fichier que j'avais commis ICI et qui comprenait un bon nombre de formats de dates :p...
Bonne suite :cool:
 

Staple1600

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Bonsoir

David84
Okette
J'enfile mon fouet et mets mon chapeau à la ceinture, et m'en vais de ce pas à recherche du Pattern perdu.











[digression qu'il n'est pas forcément utile de lire]
Une question avant de partir chercher ce Graal regexpien
Est-ce un hasard, si c'est en 2012, que tu t’intéresses aux dates et notamment à l'année 2199, ou dois-je y voir un coup des Incas/Mayas/Olmèques qui nous annonce la fin (certains seraient tentés de dire enfin pas trop) de notre si joli monde en 2012.

Et toi, David84, tel Goliath62 (le frère d'Ulysse31), tu veux conjurer le sort en nous faisant miroiter l'an 2199 tout en nous affriolant avec des patterns des plus suggestifs.

Sache que si tel est ton dessein, je veux bien conjurer avec toi et même te faire une place dans mon bunker mais tu devras laisser tes patterns sur le palier.
[/digression]
 

david84

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Re
@staple:)
Et toi, David84, tel Goliath62 (le frère d'Ulysse31), tu veux conjurer le sort en nous faisant miroiter l'an 2199 tout en nous affriolant avec des patterns des plus suggestifs.

Sache que si tel est ton dessein, je veux bien conjurer avec toi et même te faire une place dans mon bunker mais tu devras laisser tes patterns sur le palier.
Franchement, sans pattern la vie te semblerait bien austère:rolleyes:...

Sinon, concernant le code produit, si l'on s'en tient expressément à la recherche de dates valides telles que présentée dans le fichier, l'emploi de Test suffit à vérifier la validité de la chaîne :

Code:
Function DateValide(MaChaine As String) As Boolean
Dim oRegExp, Resultat
  'Application.Volatile 'recalcul automatique
  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
   
Set oRegExp = Nothing
Set Resultat = Nothing

End Function

@JNP:)
j'espère que tu as désossé le petit fichier que j'avais commis ICI et qui comprenait un bon nombre de formats de dates ...
Je m'y suis mis et ai fini par comprendre.
C'est très instructif mais ça vole haut !
Mes compliments pour la maîtrise du sujet.

A+
 

Staple1600

XLDnaute Barbatruc
Re : Expressions régulières - Patterns pour RegExp

Bonsoir

David84
Et sans IIF aussi, austère ma cellule serait ;)

Pour le plaisir de te croiser, je me permets cette petite récréation
Code:
Function DateValide(MaChaine As String) As Boolean
  'Application.Volatile 'recalcul automatique
     With CreateObject("vbscript.regexp")
      .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
      DateValide = IIf(.test(MaChaine), True, False)
    End With
End Function
Si je me trompe tu n'utilises pas Resultat, non ?

Code:
Private Sub aquatik(ParamArray MesDates())
Dim i As Byte
For i = 0 To UBound(MesDates)
MsgBox DateValide(CStr(MesDates(i)))
Next i
End Sub
Code:
Sub test()
aquatik "David84", "32/02/2011", "29/02/2012", "01/01/2190", "01/01/1901"
End Sub

En tout cas bravo à toi pour ce pattern si limpide à comprendre du premier coup d'oeil ;)

PS: Mes salutations à JNP, un grand patternaliste devant l'Ethernet ;)
 
Dernière édition:

Statistiques des forums

Discussions
315 096
Messages
2 116 183
Membres
112 677
dernier inscrit
Justine11