Les Expressions Rationnelles appliquées en VBA AccessDate de publication : 28/02/2006 , Date de mise à jour : 28/02/2006 Thèmes abordés : I. Introduction I-A. Mais de quoi parle-t-on ? I-B. Mais à quoi ça sert ? I-C. Les contributions de Developpez.com sur les RegExp II. La bibliothèque Microsoft VBScript Regular Expressions II-A. Présentation théorique II-A-1. Les propriétés II-A-1-a. Pattern (chaîne) II-A-1-b. Multiline (booléen) II-A-1-c. IgnoreCase (booléen) II-A-1-d. Global (booléen) II-A-2. Les méthodes II-A-2-a. Test (validation) II-A-2-b. Execute (exploration) II-A-2-c. Replace (remplacement) II-B. Présentation par la pratique III. L'écriture d'expressions rationnelles III-A. Apprentissage par la pratique : les titres de film III-A-1. Analysons un peu ... III-A-2. Capturer du texte III-A-3. Optimisation III-A-4. Remplacement III-B. Apprentissage par la pratique : une adresse ip valide III-B-1. Analysons un peu ... III-B-2. Quantifions III-B-3. la Classe des RegExp III-B-4. les alternatives III-B-5. Dénouement III-C. Compléments théoriques III-C-1. Positions III-C-2. Symboles III-C-3. Classes III-C-4. Quantifieurs III-C-5. Alternatives et Groupements III-C-6. Références IV. Cas pratique : la coloration syntaxique IV-A. Cahier des charges IV-B. Eléments à colorer IV-C. Analyse des éléments IV-C-1. Les mots clés IV-C-2. Les commentaires IV-C-3. Les types IV-C-4. Les chaînes IV-C-5. HTML & Nettoyages divers IV-D. La fonction d'export avec coloration syntaxique V. Conclusion I. IntroductionI-A. Mais de quoi parle-t-on ?
Le sujet de ce tutoriel est l'implémentation dans Access des expressions rationnelles également nommées expressions régulières de l'anglais Regular Expressions qu'on abrège communément en RegEx ou RegExp. C'est un système de notation extrêmement puissant issu du monde UNIX qui a été conçu pour parcourir des chaînes, d'y trouver des sous-chaînes définies par des motifs et éventuellement de procéder à des remplacements. I-B. Mais à quoi ça sert ?
Suite à une question posée sur le forum Access. Bonsoir tout le monde !! J'ai dans un logiciel de vidéothèque une table dont le titre est stocké de la façon suivante titrefilm (article) Exemple 12 TRAVAUX D'ASTÉRIX (LES) Comment faire pour récupérer le titre sans l'article dans une requete ?? Quand l'auteur de la question dit : "titrefilm (article)" il définit ce qu'on appelle un motif et il ne reste plus qu'à le formaliser en langage RegExp. On pourrait très bien proposer une fonction VBA avec un InstrRev() sur la parenthèse ouvrante, mais la solution RegExp reste de très loin plus élégante et puissante. Dans cet article, le cas pratique retenu est la coloration syntaxique. En effet, si nous souhaitons effectuer un export d'un module de code en y mettant une "intelligence" par la coloration syntaxique, nous prenons conscience de la difficulté de la tâche. Par exemple : repérer des sous-chaînes entre double-quotes (") exige soit d'effectuer plusieurs séries de Split() soit de parcourir la chaîne, caractère par caractère. L'utilisation d'expressions rationnelles nous soulage de cette complexité. I-C. Les contributions de Developpez.com sur les RegExp
N'hésitez pas à consulter les articles de mes confrères sur le même sujet dans leur langage respectif. II. La bibliothèque Microsoft VBScript Regular Expressions
Microsoft Access n'inclue pas les regexp de manière native puisque nous avons vu qu'elles viennent de l'univers Unix. Cependant pour parer à cette lacune, Microsoft a mis à disposition une bibliothèque de code : Microsoft VBScript Regular Expressions. La première étape consiste à l'ajouter à vos références de projet, dans l'éditeur : Menu Outils > Reférences ... ![]() Ajout de la référence VBScript Regular Expressions II-A. Présentation théorique
L'expression rationnelle vise à repérer une ou plusieurs structures identifiées au sein d'une chaîne de caractères. Ce repérage se fait au moyen de la définition d'un motif (Pattern). Les fonctions possibles sont ensuite la validation, l'exploration et les remplacements. II-A-1. Les propriétésII-A-1-a. Pattern (chaîne)
C'est la propriété qui définit le motif sur lequel se fait la recherche.
Il vous faut bien évidement la définir avant d'exploiter les recherches, la validation ou les remplacements.
II-A-1-b. Multiline (booléen)
Active ou non la recherche sur plusieurs lignes à la fois.
La propriété est mise sur False par défaut. Il vous faut bien évidement la définir avant d'exploiter les recherches, la validation ou les remplacements.
II-A-1-c. IgnoreCase (booléen)
Précise si la recherche est sensible ou non à la casse (majuscules/minuscules).
La propriété est mise sur False par défaut. Il vous faut bien évidement la définir avant d'exploiter les recherches, la validation ou les remplacements.
II-A-1-d. Global (booléen)
Précise si la recherche porte sur la première occurence ou sur toutes.
La propriété est mise sur False par défaut. Il vous faut bien évidement la définir avant d'exploiter les recherches, la validation ou les remplacements.
II-A-2. Les méthodesII-A-2-a. Test (validation)
C'est une méthode qui renvoie un booléen.
.Test renvoie True si le motif défini en Pattern est trouvé dans la chaîne.
La boîte de dialogue renverra True puisque "a" est bien contenu dans la chaîne "papa". II-A-2-b. Execute (exploration)
Cette méthode permet d'explorer les occurences qui vérifient le Pattern.
L'argument de la méthode est la chaîne sur laquelle nous travaillons. Nous pouvons ensuite parcourir : . la collection des correspondances (MatchCollection) . les sous-correspondances (SubMatches) comme dans l'exemple ci-dessous.
Ce qui donnera :
II-A-2-c. Replace (remplacement)
C'est une méthode qui renvoie une chaîne.
Les arguments de la méthode sont : - la chaîne sur laquelle nous travaillons - la chaîne qui définit le remplacement avec les éventuelles variables de sous-motifs. Les regexp autorisent la définition de sous-motifs entre parenthèses, ils sont matérialisés par des variables de type Perl $x : xième sous-motif.
Le code renverra la chaîne : "douze travaux d'Astérix (les)". II-B. Présentation par la pratique
Ce qui donne en mode exécution :
Nous utiliserons cette fonction AllRegexp() dans la partie suivante pour tester nos regexp. III. L'écriture d'expressions rationnelles
Si les RegExp sont un outil vraiment puissant, il faut se rendre à l'évidence que l'écriture des motifs (patterns) peut s'avérer rebutante pour le néophyte. Pas de panique cependant, il s'agit d'un langage obéissant à des règles. Je vous propose de vous y initier au moyen de deux exemples précis : - une réécriture de titre de films - une validation d'adresse ip. III-A. Apprentissage par la pratique : les titres de film
Vous vous souvenez de la question posée sur le forum, rappelée en introduction de l'article ? Comment transformer de manière automatique ceci : douze travaux d'Astérix (les) en les douze travaux d'Astérix III-A-1. Analysons un peu ...
Schématisons l'expression à transformer de la manière la plus générale possible?
Nous avons le titre sur plusieurs mots, puis un espace, puis un article entre parenthèses. Soit 3 blocs que nous allons isoler dans des parenthèses (choix stratégique que vous allez comprendre après). (titre sur plusieurs mots)(caractère espace)((article entre parenthèses))
Etant donné que les parenthèses sont des caractères réservés, pour repérer ces caractères, nous devons les échapper en plaçant devant un antislash \
Nous corrigeons notre expression comme suit : (titre sur plusieurs mots)(caractère espace)(\(un ou plusieurs mots\)) III-A-2. Capturer du texte
Pour récupérer un ou plusieurs mots / caractères nous utilisons : .*
Reformulons notre notation compte tenu de ces principes. (.*)( )(\(.*\)) Appliquons notre notation avec la fonction AllRegex() définie en partie II-B.
Le motif est valide : indiqué par Vrai sur la méthode .Test Les variables sont $1, $2 et $3 sont conformes à nos attentes formulées lors de l'analyse.
III-A-3. Optimisation
Dans ce cas précis, nous sommes parvenus à détacher en une seule instruction : le titre et l'article ; malheureusement l'article reste entre parenthèses.
Du fait que nous souhaitons l'isoler, nous allons donc sortir les parenthèses de notre capture en définissant le nouveau motif comme suit : (.*) \((.*)\) Nous excluons les caractères inutiles de notre recherche en les sortant des parenthèses capturantes, à savoir l'espace et les parenthèses.
III-A-4. Remplacement
Notre chaîne est correctement découpée, il ne nous reste plus qu'à la reconstituer.
.Execute nous permet d'identifier les sous-motifs avec leurs noms de variable Perl. $1 = "douze travaux d'Astérix" (en abstration le titre) $2 = "les" (en abstraction l'article) Le reconstitution se fait par la méthode .Replace Il suffit de préciser ce que nous souhaitons en sortie sous forme d'une chaîne incluant les variables, soit : "$2 $1" Ce qui donne :
Mission accomplie !
III-B. Apprentissage par la pratique : une adresse ip valide
Voici maintenant une réponse posée à une autre question du forum. Comment puis-je m'assurer que l'adresse ip fournie est valide ? III-B-1. Analysons un peu ...
Comme lors du cas précédent, la réponse à notre problème exige un peu d'analyse. Qu'est-ce qu'une adresse ip ? Quelques exemples : 122.123.1.250, 251.110.255.255 ... Il s'agit de 4 entiers inférieurs ou égaux à 255 séparés par des points. Schématisons : (entier <= 255).(entier <= 255).(entier <= 255).(entier <= 255) III-B-2. Quantifions
Il est aisé de voir que la structure d'une ip est un motif répétitif. Les RegExp sont parfaitement adaptées à ce cas puisqu'elles permettent de simplifier l'écriture, la factoriser. Reprenons : ((entier <= 255).)3 fois (entier <= 255) Cette quantification se fait grâce aux accolades {} et se note donc : ((entier <= 255).){3}(entier <= 255)
III-B-3. la Classe des RegExp
Il nous faut maintenant formuler ce qu'est un entier <=255 Les RegExp travaillent sur des chaînes et non pas sur des numériques, nous ne pourrons donc pas tester une valeur. En revanche un entier <=255 peut couvrir les types de chaînes suivantes : - un chiffre (digit) : entre 0 et 9 - deux chiffres (digit) : entre 0 et 9 et entre 0 et 9, soit les valeurs 0 -> 99 - trois chiffres (digit) : - si le premier chiffre est un 1 : les suivants peuvent se situer entre 0 et 9, soient les valeurs 100 -> 199 - si le premier chiffre est un 2 : le second devra être compris entre 0 et 5 - si le second est entre 0 et 4 : le troisième pourra se situer entre 0 et 9, soient les valeurs 200 -> 249 - si le second est un 5 : le troisième devra se situer entre 0 et 5, soient les valeurs 250 -> 255 Nous couvrons à présent tout l'éventail des possibilités.
Par conséquent, un chiffre entre 0 et 9 peut s'écrire [0-9] Et un chiffre entre 0 et 5 : [0-5]
III-B-4. les alternatives
Nous avons décomposé les chaînes possibles d'un entier <= 255
entre 0 et 9 s'écrit \d (classe des Digit) entre 0 et 99 s'écrit \d?\d entre 000 et 199 s'écrit 1?\d?\d entre 200 et 249 s'écrit 2[0-4]\d entre 250 et 255 s'écrit 25[0-5] Il faut maintenant indiquer que nous voulons ces trois cas.
Réécrivons notre entier : (25[0-5]|2[0-4]\d|1?\d?\d)
III-B-5. Dénouement
Nous sommes parvenus à formaliser notre entier.
Dernière information le . est un idenficateur, nous devons donc « l'échapper » avec l'antislash. Ce qui donne : ^((25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(25[0-5]|2[0-4]\d|1?\d?\d)$ Mettons le à l'épreuve :
Mission accomplie.
III-C. Compléments théoriques
C'est la partie un petit peu plus aride du tutoriel, mais il est utile de synthétiser les outils de notation mis à disposition par la bibliothèque RegExp. Bon courage ! III-C-1. Positions
III-C-2. Symboles
III-C-3. Classes
III-C-4. Quantifieurs
III-C-5. Alternatives et Groupements
III-C-6. Références
IV. Cas pratique : la coloration syntaxique
Nous allons appliquer notre savoir-faire fraichement acquis dans un cas pratique : la coloration syntaxique.
IV-A. Cahier des charges
Notre projet a pour but de pouvoir documenter notre code sur le net, pour cela nous souhaitons pouvoir exporter des modules de code au format HTML. Il s'avère qu'un code n'est rien d'autre qu'un fichier texte. On pourrait se contenter d'un simple export, mais il faut avouer que le rendu n'est pas très intéressant. ![]() Export simple d'un module de code Nous souhaitons donc avoir un rendu visuel plus proche de celui de l'éditeur VBA qui utilise la coloration syntaxique. C'est à dire qu'un mot clé est reconnu et prend une couleur particulière. ![]() L'éditeur VBA et la coloration syntaxique IV-B. Eléments à colorer
L'IDE de programmation VBA comprend par défaut 3 niveaux de coloration : - Le mot clé de langage VBA : nativement en bleu (ex : Then) - Le commentaire signalé par un quote (') hors chaîne : nativement en vert - Le reste du langage : nativement en noir. Nous allons améliorer ce process et ajouter deux nouvelles catégories : - Les chaînes : tout texte compris entre deux double quotes (") - Les types de données : exemple Boolean, Byte ou Integer. IV-C. Analyse des élémentsIV-C-1. Les mots clés
Un mot clé appartient à une liste prédéfinie.
Nous remarquons au passage que tous les mots clés VBA ne sont pas, loin de là, affectés par une coloration syntaxique. Par exemple, Left() fonction de chaîne ô combien connue n'est pas colorée. Il nous faut donc parcourir notre chaîne pour trouver les occurences des mots en questions. Ces mots peuvent être : - en début de ligne - en fin de ligne - délimités par les caractères suivants : " .()" [espace][point][parenthèse ouvrante][parenthèse fermante] Nous définissons donc le tableau des mots-clés à colorer et pour chacun nous allons appliquer un remplacement RegExp. Le pattern sera :
Explications : Nous découpons le regexp en 3 parties : - (\W|^) : Soit un caractère qui n'est pas de la classe Word [a-zA-Z_0-9] Soit un début de chaîne - "(" & KeyWords(i) & ")" : parcours du tableau de mots-clés - (\W|$) : Soit un caractère qui n'est pas de la classe Word [a-zA-Z_0-9] Soit une fin de chaîne
Ce qui aboutit à mettre entre nos balises de style span le mot clé.
IV-C-2. Les commentaires
Un commentaire en VB / VBA est simplement matérialisé par une apostrophe (') ou un REM en début de ligne.
Il faut bien sûr que cette apostrophe ne soit pas comprise à l'intérieur de deux double-quotes (") sinon elle est inclue à la chaîne. L'éditeur VBA colore jusqu'à la fin de ligne. Le commentaire peut prendre toute la ligne ou bien la fin seulement.
Explications : Nous découpons cette fois en 4 parties principales (dont une imbriquée) : - (\n) : nous recherchons un retour à la ligne, par conséquent un début de ligne - (([^\x22\n]*\x22[^\x22\n]*\x22)*) : - pour mémoire \xZZ indique un caractère de code hexa ZZ dans notre cas 22 en hexa = 34 en décimal, soit le caractère double-quote (") - la section [^\x22\n]*\x22*[^\x22\n]*\x22 autorise qu'une partie à gauche de l'apostrophe est une chaîne VB comprise entre double-quotes (") - ([^\x22\n']*) : nous utilisons une classe pour exclure certains caractères grâce à ^ : les guillemets ("), le retour à la ligne et l'apostrophe. Nous sommes donc certains de ne pas nous situer dans une chaîne entre double-quotes et d'obtenir la première apostrophe de l'expression. - ('.*) : nous capturons toute chaîne précédée de l'apostrophe (') Ce qui aboutit au remplacement suivant :
Il nous reste à gérer les commentaires précédés du mot-clé REM. Pour la réperer, il s'agit d'une ligne entamée par REM suivi d'un espace puis le commentaire, le tout précédé ou non par des espaces ou tabulations. - la classe des caractères de type "espace" est \s ; - pour quantifier "aucun ou plusieurs" nous utilisons * ; - pour capturer ce qui suit REM nous cherchons n'importe quel caractère (le point : .) répété 0 ou plusieurs fois (l'astérisque : *) : .* Nous obtenons le motif suivant : (\s*)(REM .*)
IV-C-3. Les types
Cette distinction n'est pas native dans VB / VBA, nous allons mettre en gras les types de données.
La méthode est rigoureusement identique à celle des mots clés. Nous utilisons cette fois un autre tableau Types().
IV-C-4. Les chaînes
Là encore, la coloration syntaxique n'est pas native dans VB / VBA, mais cela rend le code beaucoup plus lisible.
Il nous faut récupérer simplement une chaîne comprise entre deux double-quotes (") et qui ne contient pas elle-même de double-quote.
Nous récupérons un seul bloc délimité par les double-quotes (") et qui ne contient pas lui même ce caractère ou un retour à la ligne. Et voici le remplacement simplissime :
IV-C-5. HTML & Nettoyages diversAvant d'ajouter du code HTML nous évitons de nous faire polluer le balisage en remplaçant < par <
Les retours chariot VB ne s'appliquent pas en HTML. Nous devons les matérialiser en repérant le retour chariot (\n) auquel nous ajoutons <br />
Autre nettoyage, les tags imbriqués. En effet notre code risque d'engendrer des colorations syntaxiques de mot-clés dans une chaîne ou dans un commentaire. Nous allons y remédier : - le motif recherché sera situé entre les balises span (<span class=.*>)(.*)(</span>). - au lieu de .* nous utilisons \w{6,11} et indiquer un mot comprenant entre 6 et 11 caractères ce qui évite de récupérer le style 'key' et le style 'type'. - nous capturons un autre tag de style (\w{3,11}) avec cette fois entre 3 et 11 caractères pour pouvoir neutraliser tous les styles, y compris 'key' et 'type'
Nous passons une boucle sur le remplacement pour nettoyer toutes les occurences. Dernière modification : les espaces. Un simple remplacement de deux espaces contigus par un double caractère 160 suffit.
IV-D. La fonction d'export avec coloration syntaxique
V. Conclusion
J'espère que ce tutoriel vous donnera envie de mieux connaître les expressions rationnelles, ou mieux vous aura permis de débloquer des situations complexes. Merci aux membres de la rédaction pour leurs relectures attentives. Et merci à tous de m'avoir lu ;-) |
Les sources présentées sur cette page sont libres de droits, et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 Charles A.. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.