Windows PowerShellÉcriture d'expressions régulières

Don Jones

192.168.4.5. \\Server57\Share. johnd@contoso.com. Vous reconnaissez sans doute ces trois éléments comme étant une adresse IP, un chemin UNC (Universal Naming Convention) et une adresse e-mail. Votre cerveau reconnaît leur format. Quatre groupes de chiffres, des barres obliques inverses, le symbole @ et d'autres indices indiquent quels types de données ces chaînes de

caractères représentent. Sans avoir à réfléchir beaucoup, vous pouvez reconnaître rapidement que 192.168 seul n'est pas une adresse IP valide, que 7\\Server2\\Share n'est pas une UNC valide et que joe@contoso n'est pas une adresse e-mail valide.

Malheureusement, les ordinateurs ont plus de mal à « comprendre » des formats compliqués comme ceux-ci. C'est là qu'entrent en jeu les expressions régulières. Une expression régulière est une chaîne, écrite à partir d'un langage d'expression régulière spécial, qui aide un ordinateur à identifier des chaînes qui présentent un format particulier (par exemple, une adresse IP, une UNC ou une adresse e-mail). Une expression régulière bien écrite peut permettre à un script Windows PowerShellTM d'accepter ou de rejeter des données selon qu'elles sont conformes ou non au format que vous avez spécifié.

Correspondance simple

L'opérateur de correspondances -match Windows PowerShell compare une chaîne à une expression régulière (regex), puis renvoie une réponse True (Vrai) ou False (Faux) selon que la chaîne correspond ou non à l'expression régulière. Une expression régulière très simple n'a même pas besoin de contenir une syntaxe spéciale : des caractères littéraux suffiront. Par exemple :

"Microsoft" –match "soft"
"Software" –match "soft"
"Computers" –match "soft"

Lorsqu'elles sont exécutées dans Windows PowerShell, les deux premières expressions renvoient True (Vrai) tandis que la troisième renvoie False (Faux). Dans chaque expression, une chaîne est suivie par l'opérateur –match, lui-même suivi par une expression régulière. Par défaut, une expression régulière flottera sur une chaîne pour trouver une correspondance. Les caractères « soft » se retrouvent dans Software (Logiciel) et Microsoft, mais dans des positions différentes. Notez également que, par défaut, une expression régulière n'est pas sensible à la casse : « soft » se trouve dans « Software » malgré son S majuscule.

Mais si nécessaire, un opérateur différent, –cmatch, offre une comparaison d'expressions régulières sensible à la casse, comme ceci :

"Software" –cmatch "soft"

Cette expression renvoie la réponse False (Faux) puisque la chaîne « soft » ne correspond pas à « Software » dans une comparaison sensible à la casse. Notez que l'opérateur -imatch est également disponible comme option insensible à la casse explicite, bien qu'il s'agisse du comportement par défaut de –match.

Caractères génériques et répéteurs

Une expression régulière peut contenir plusieurs caractères génériques. Un point, par exemple, correspond à une instance de n'importe quel caractère. Un point d'interrogation correspond à zéro ou une instance de n'importe quel caractère. Voici quelques exemples à titre d'illustration :

"Don" –match "D.n" (True)
"Dn" –match "D.n" (False)
"Don" –match "D?n" (True)
"Dn" –match "D?n" (True)

Dans la première expression, le point correspond à un caractère exactement, donc la correspondance est True (Vrai). Dans la seconde expression, le point ne trouve pas le caractère dont il a besoin, donc la correspondance est False (Faux). Le point d'interrogation, présent dans les troisième et quatrième expressions, peut correspondre à un seul caractère inconnu ou aucun caractère. Enfin, dans le quatrième exemple, la correspondance est True (Vrai) parce que « D » et « n » n'ont pas de caractère entre eux. Ainsi, le point d'interrogation peut être considéré comme représentant un caractère facultatif, donc la correspondance reste True (Vrai) même si aucun caractère n'apparaît à cet endroit.

Une expression régulière reconnaît également les symboles * et + comme des répéteurs. Ceux-ci doivent suivre un ou des caractère(s) spécifique(s). Le symbole * correspond à zéro ou plusieurs des caractères spécifiés, tandis que le + correspond à un ou plusieurs des caractères spécifiés. Voici quelques exemples :

"DoDon" –match "Do*n" (True)
"Dn" -match "Do*n" (True)
"DoDon" -match "Do+n" (True)
"Dn" -match "Do+n" (False)

Notez que * et + correspondent à « Do », et pas seulement au « o ». C'est parce que ces répéteurs sont conçus pour correspondre à une série de caractères, et non un seul caractère.

Qu'en est-il si vous devez établir une correspondance avec les symboles ., *, ? ou + à proprement parler ? Il vous suffit de les précéder d'une barre oblique inverse, qui est le caractère d'échappement des expressions régulières :

"D.n" -match "D\.n" (True)

Notez qu'il est différent du caractère d'échappement de Windows PowerShell (l'apostrophe ascendante), mais qu'il suit la syntaxe des expressions régulières normalisée.

Classes de caractères

Une classe de caractères est une forme plus large de caractères génériques, représentant un groupe entier de caractères. Windows PowerShell reconnaît plusieurs classes de caractères. Par exemple :

  • \w correspond à n'importe quel caractère de mot, c'est-à-dire les lettres et chiffres.
  • \s correspond à n'importe quel caractère d'espace blanc, par exemple les tabulations, les espaces, et ainsi de suite.
  • \d correspond à n'importe quel chiffre.

On distingue également des classes de caractères négatifs : \W correspond à un caractère de non mot, \S correspond à un caractère de non espace blanc et \D correspond à un non chiffre. Ces classes peuvent être suivies par * ou + pour indiquer que plusieurs correspondances sont acceptables. Voici quelques exemples :

"Shell" -match "\w" (True)
"Shell" -match "\w*" (True)

Applet de commande du mois

L'applet de commande Write-Debug est très pratique pour l'écriture d'objets (tels que les chaînes de texte) dans le pipeline Debug. Toutefois, il peut être décevant d'essayer cette applet de commande dans l'environnement de ligne de commande, parce qu'on a l'impression que l'applet de commande ne sert à rien.

En fait, le pipeline Debug est bloqué par défaut : la variable $DebugPreference est réglée sur « SilentlyContinue ». Si vous la réglez sur « Continue », tout ce que vous envoyez avec Write-Debug apparaîtra en jaune dans la console. C'est une façon idéale d'ajouter un code de suivi à vos scripts, ce qui vous permet de suivre l'exécution d'un script complexe. La couleur jaune vous aide à distinguer le suivi de la sortie normale du script et vous pouvez bloquer les messages de débogage à tout moment sans avoir à supprimer toutes les instructions Write-Debug. Il vous suffit de régler $DebugPreference sur « SilentlyContinue » à nouveau et le texte de débogage sera éliminé.

Bien que les deux expressions renvoient le résultat True (Vrai), elles correspondent à des choses fort différentes. Heureusement, il y existe un moyen de décrypter l'opérateur -match : à chaque fois qu'une correspondance est établie, une variable spéciale appelée $matches est peuplée avec les résultats de la correspondance, c.-à-d. les caractères de la chaîne pour lesquels l'opérateur a établi une correspondance avec votre expression régulière. La variable $matches retient ses résultats jusqu'à ce qu'une autre correspondance positive soit établie avec l'opérateur -match. La figure 1 illustre la différence entre les deux expressions que je viens de vous montrer. Comme vous pouvez le voir, \w correspondait au « S » de « Shell », tandis que le \w* répété correspondait au mot entier.

Figure 1 Différence engendrée par le symbole *

Figure 1 Différence engendrée par le symbole *  (Cliquer sur l'image pour l'agrandir)

Groupes, plages et tailles de caractères

Une expression régulière peut également contenir des groupes ou plages de caractères placés entre crochets. Par exemple, [aeiou] signifie que n'importe lequel des caractères inclus (a, e, i, o, ou u) est une correspondance acceptable. [a-zA-Z] indique que n'importe quelle lettre de la plage a-z ou A-Z est acceptable (toutefois, si vous utilisez l'opérateur –match non sensible à la casse, a-z ou A-Z seul suffirait). Voici un exemple :

"Jeff" -match "J[aeiou]ff" (True)
"Jeeeeeeeeeeff" -match "J[aeiou]ff" (False)

Vous pouvez également spécifier un nombre minimal et maximal de caractères à l'aide d'accolades. {3} Indique que vous voulez exactement trois exemplaires du caractère spécifié, {3,} signifie que vous voulez au moins trois exemplaires ou plus et {3,4} indique que vous voulez au moins trois exemplaires, mais pas plus de quatre. C'est une façon idéale de créer une expression régulière pour les adresses IP :

"192.168.15.20" -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" (True)

Cette expression régulière veut quatre groupes de chiffres contenant chacun un à trois chiffres, tous séparés par un point. Mais regardez cet exemple :

"300.168.15.20" -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" (True)

Il montre les limites des expressions régulières. Bien que le formatage de cette chaîne corresponde à celui d'une adresse IP, il ne s'agit évidemment pas d'une adresse IP valide. Une expression régulière ne peut pas déterminer si des données sont valides ; elle peut seulement déterminer si le formatage des données est correct.

Arrêt du flottement

Le dépannage d'une expression régulière n'est pas toujours évident. Voici par exemple une expression régulière qui teste un chemin UNC dans le format \\Server2\Share :

"\\Server2\Share" -match "\\\\\w+\\\w+" (True)

Ici, l'expression régulière elle-même est difficile à lire parce que chaque barre oblique inverse que je veux tester doit être échappée avec une deuxième barre oblique inverse. Bien que cela ait l'air de marcher, ce n'est vraiment pas le cas :

"57\\Server2\Share" -match "\\\\\w+\\\w+" (True)

Ce second exemple n'est clairement (au moins pour vous et moi) pas un chemin UNC valide, mais l'expression régulière l'a validé. Pourquoi ? Souvenez-vous que les expressions régulières flottent par défaut. Cette expression régulière recherche simplement deux barres obliques inverses, une lettre et un chiffre ou plus, une autre barre oblique inverse, et d'autres lettres et chiffres. Ce modèle existe dans la chaîne, ainsi que les chiffres supplémentaires au début, qui en font un chemin UNC non valide. En fait, il faut dire à l'expression régulière de commencer à effectuer la correspondance au début de la chaîne, sans flotter. Je peux procéder de la façon suivante :

"57\\Server2\Share" -match "^\\\\\w+\\\w+" (False)

Le caractère ^ indique l'endroit où commence la chaîne. Avec cet ajout, le chemin UNC non valide échoue parce que l'expression régulière recherche deux barres obliques inverses comme premiers caractères et ce n'est pas le cas ici.

De même, le symbole $ peut être utilisé pour indiquer la fin d'une chaîne. Ceci ne serait pas très utile dans le cas d'un chemin UNC puisqu'un chemin UNC peut contenir des segments de chemin supplémentaires, tels que \\Server2\Share\Folder\File, par exemple. Cependant, je suis sûr qu'il y a de nombreux cas où vous souhaiteriez spécifier la fin d'une chaîne.

Aide pour les expressions régulières

Dans Windows PowerShell, la rubrique d'aide about_regular_expressions fournit une aide à la syntaxe fondamentale pour le langage des expressions régulières, mais les ressources en ligne vous fourniront encore plus d'informations. Ainsi, l'un de mes sites Web préférés, www.RegExLib.com, propose une bibliothèque gratuite d'expressions régulières qui ont été écrites dans des buts divers par le public. Vous pouvez effectuer des recherches par mots-clés, tels que « e-mail » ou « UNC » pour trouver rapidement une expression régulière adaptée à vos besoins, ou au moins pour démarrer. Si vous parvenez à créer une bonne expression régulière, vous pouvez la proposer à la bibliothèque pour que d'autres puissent l'utiliser.

J'aime également RegexBuddy (www.RegexBuddy.com). Il s'agit d'un outil bon marché qui fournit un éditeur graphique d'expressions régulières. RegexBuddy facilite non seulement l'assemblage d'une expression régulière complexe, mais également les tests d'expressions régulières pour s'assurer qu'elles acceptent les chaînes valides et rejettent les chaînes non valides correctement. Plusieurs autres développeurs de logiciels ont également créé des éditeurs et testeurs d'expressions régulières, gratuits, contributifs ou commerciaux que les utilisateurs trouveront certainement utiles.

Utilisation des expressions régulières

Vous vous demandez peut-être dans quelles circonstances vous utiliseriez une expression régulière dans la vie de tous les jours. Imaginez que vous lisez des informations dans un fichier CSV et que vous utilisez ces informations pour créer de nouveaux utilisateurs dans Active Directory®. Si le fichier CSV est généré par quelqu'un d'autre, vous souhaiterez être sûr que les données contenues dans le fichier présentent un formatage correct. Une expression régulière peut s'en charger. Une expression régulière simple telle que \w+, par exemple, peut confirmer que le prénom et le nom ne contiennent pas de caractères spéciaux ou de symboles, et une expression régulière plus complexe peut confirmer que les adresses e-mail sont conformes à la norme de votre entreprise. Vous pourriez par exemple utiliser ceci :

"^[a-z]+\.[a-z]+@contoso.com$"

Cette expression régulière nécessite une adresse e-mail sous la forme don.jones@contoso.com, où le prénom et le nom peuvent contenir uniquement des lettres et où ils doivent être séparés par un point. Á ce propos, les adresses e-mail sont les chaînes les plus difficiles pour l'écriture d'expressions régulières. Si vous pouvez restreindre votre objectif à une norme d'entreprise spécifique, ce sera plus facile.

N'oubliez pas ces points d'ancrage de début et de fin (^ et $), qui garantissent que rien ne suit contoso.com et que rien ne précède les caractères composant le prénom de l'utilisateur.

En fait l'utilisation de cette expression régulière dans Windows PowerShell est relativement simple. Si l'on suppose que la variable $email contient l'adresse e-mail que vous lisez dans le fichier CSV, une expression régulière du type suivant vérifiera sa validité :

$regex = "^[a-z]+\.[a-z]+@contoso.com$"
If ($email –notmatch $regex) {
  Write-Error "Invalid e-mail address $email" 
}

Et dans cet exemple, vous avez appris un nouvel opérateur. -notmatch renvoie la réponse True (Vrai) si la chaîne ne correspond pas à l'expression régulière fournie. (Il existe aussi –cnotmatch pour les comparaisons sensibles à la casse.)

Il y a encore beaucoup à dire sur les expressions régulières : d'autres classes de caractères, des opérations plus avancées et même l'un ou l'autre opérateur. Il y a aussi le type d'objet [regex] pris en charge par Windows PowerShell. Toutefois, ce dont j'ai parlé dans cet aperçu rapide de la syntaxe des expressions régulières devrait vous suffire pour démarrer. N'hésitez pas à me rendre visite sur www.ScriptingAnswers.com si vous avez besoin d'aide pour une expression régulière particulièrement difficile.

Don Jones contribue à l'élaboration de TechNet Magazine et est le coauteur de Windows PowerShell: TFM (SAPIEN Press). Il enseigne Windows PowerShell (www.ScriptingTraining.com) et peut être contacté par le biais du site Web ScriptingAnswers.com.

© 2008 Microsoft Corporation et CMP Media, LLC. Tous droits réservés. Toute reproduction, totale ou partielle, est interdite sans autorisation préalable.