Hé, vous le scripteur !Des sourcils et des expressions régulières

Les scripteurs Microsoft

Télécharger le code de cet article: HeyScriptingGuy2008_05.exe (150KB)

En novembre 2007 , nous autres scripteurs avons eu l'occasion de passer une journée à Paris lors notre voyage à destination de la conférence Tech•Ed IT organisée à Barcelone. Nous avons profité de notre escale d'une journée pour visiter le Louvre, le musée d'art de renommée mondiale.

Comment avons-nous trouvé le Louvre ? C'est simple : nous avons marché jusqu'à Notre-Dame et avons ensuite pris à gauche.

Oh, vous vous demandez en fait si nous avons apprécié le Louvre ? En grande partie, oui. Le seul problème que nous avons eu, c'est que le Louvre, comme beaucoup de musées, fonctionne sur le principe du « on regarde mais on ne touche pas ». Tout le monde sait que la Joconde serait beaucoup plus belle si elle avait des sourcils, mais, pour une raison quelconque, les gens qui s'occupent du Louvre deviennent vraiment très vexés si vous essayez de corriger le moindre de leurs tableaux.

Remarque : en fait, nous avons tous deux aimé la Joconde. C'était une surprise agréable, d'ailleurs. Après tout le battage médiatique et l'anticipation, nous avions peur qu'il ne s'agisse que d'un tableau comme les autres. Mais ce n'était pas le cas ; c'est vraiment un superbe tableau (même si elle aurait bien besoin de sourcils). Ce qui est intéressant, cependant, c'est que nous avons tous deux été déçus par tout le battage autour de la Vénus de Milo. Nous ne l'avons ni l'un ni l'autre trouvée spectaculaire et le scripteur qui écrit cette colonne était assez perplexe quant à l'idée de la Vénus de Milo. Une statue de femme qui n'a pas de bras ? Comment est-elle censée laver le plancher ou faire la vaisselle ! ?

Note à l'attention de nos lectrices (en supposant qu'il en reste) : ceci était évidemment une faute de frappe. Ce que nous voulions dire était : Une statue de femme qui n'a pas de bras ? Et pourtant elle est capable de faire le double du travail de n'importe quel homme, et de le faire correctement.

Les scripteurs vous prient de les excuser de tout malentendu que leur déclaration initiale aurait pu créer.

Quoi qu'il en soit, dès le moment où nous avons posé les yeux sur les grands trésors du Louvre, nous avons tous deux été envahis par une pensée identique : où sont les toilettes ? En les cherchant, le scripteur qui écrit cette rubrique a eu une autre pensée : les scripteurs sont des hypocrites. Après tout, nous sommes vexés que le Louvre ne nous laisse pas nous occuper de la Joconde. Et pourtant, nous sommes coupables d'un péché semblable. Dans le numéro de janvier 2008 de TechNet Magazine, nous avons écrit un article sur l'utilisation des expressions régulières dans un script. C'est un exemple typique de « on regarde mais on ne touche pas » : nous vous avons montré comment utiliser des expressions régulières pour identifier des problèmes dans un fichier texte, mais nous ne vous avons pas montré comment résoudre ces problèmes. Zut alors ! (En français dans le texte, NDT)

Remarque : si les scripteurs ont visité le Louvre en novembre 2007, comment le scripteur qui écrit cet article a-t-il pu avoir une pensée soudaine concernant un article qui n'est pas paru dans TechNet Magazine avant janvier 2008 ? Une véritable énigme, n'est-ce pas ? Cela doit sûrement être dû aux différences de fuseau horaire entre Redmond et Paris.

Heureusement, cependant, et contrairement aux gens qui gèrent le Louvre, les scripteurs reconnaissent volontiers qu'ils ont commis une erreur. Nous avons eu tort de vous montrer uniquement comment faire des recherches à l'aide d'expressions régulières. Nous aurions dû vous montrer également comment faire des remplacements avec des expressions régulières. En fait, nous aurions dû vous montrer un script tel que celui de la figure 1.

Figure 1 Rechercher et remplacer

      Set objRegEx = _
    CreateObject("VBScript.RegExp")

objRegEx.Global = True   
objRegEx.IgnoreCase = True
objRegEx.Pattern = "Mona Lisa"

strSearchString = _
    "The Mona Lisa is in the Louvre."
strNewString = _
    objRegEx.Replace(strSearchString, _
                     "La Gioconda")

Wscript.Echo strNewString 

Pour être honnête, il s'agit en fait d'une utilisation assez banale des expressions régulières : tout ce que nous faisons ici, c'est remplacer toutes les instances de la valeur de chaîne Mona Lisa par La Gioconda (mot italien signifiant « Où ai-je bien pu mettre ces sourcils ? »). Il est vrai que nous aurions pu effectuer ce remplacement beaucoup plus facilement en utilisant uniquement la fonction Replace de VBScript. Mais, n'ayez crainte : nous utiliserons ce petit script tout simple pour expliquer comment effectuer des opérations de recherche et remplacement avec les expressions régulières, et une fois que cela sera fait, nous vous montrerons certaines des choses plus sophistiquées que vous pouvez faire avec ces expressions.

Comme vous pouvez le voir, ce script n'est pas bien compliqué. Nous commençons par créer une instance de l'objet VBScript.RegExp. Inutile de dire qu'il s'agit de l'objet qui nous permet d'utiliser des expressions régulières dans un script VBScript. Après avoir créé l'objet, nous affectons des valeurs à trois des propriétés de l'objet :

Global En définissant cette propriété sur True, nous indiquons au script de rechercher (et remplacer) toutes les instances de Mona Lisa qu'il trouve dans le texte cible. Si la propriété Global était False (la valeur par défaut), le script rechercherait et remplacerait uniquement la première instance de Mona Lisa.

IgnoreCase La définition d'IgnoreCase sur True indique au script que nous voulons exécuter une recherche non sensible à la casse. En d'autres termes, nous voulons traiter mona lisa et Mona Lisa comme identiques. Par défaut, VBScript effectue une recherche sensible à la casse, ce qui signifie que, grâce aux lettres majuscules et minuscules, mona lisa et Mona Lisa sont considérés comme des valeurs complètement différentes.

Pattern La propriété Pattern contient la valeur que nous recherchons. Dans ce cas, nous recherchons seulement une valeur de chaîne simple : Mona Lisa.

Ensuite, nous affectons le texte que nous voulons rechercher à une variable nommée strSearchString :

strSearchString = "The Mona Lisa is in the Louvre."

Nous appelons alors la méthode d'expression régulière Replace, en transmettant deux paramètres à cette méthode : le texte cible que nous voulons rechercher (la variable strSearchString) et le texte de remplacement (La Gioconda). C'est ce que nous faisons ici :

strNewString = objRegEx.Replace(strSearchString, "La Gioconda")

Et c'est tout. Le texte modifié est stocké dans la variable strNewString. Si nous affichons maintenant la valeur de strNewString, nous devrions obtenir ceci :

The La Gioconda is in the Louvre.

La grammaire est quelque peu discutable, mais vous saisissez l'idée générale.

Comme nous l'avons fait remarquer plus tôt, tout ceci est bien beau, mais nous aurions sans aucun doute pu accomplir la même chose en utilisant les lignes de code suivantes (en fait, nous pourrions même tout faire en une seule ligne si nous le souhaitions) :

strSearchString = "The Mona Lisa is in the Louvre."
strNewString = Replace(strSearchString, "Mona Lisa", "La Gioconda")
Wscript.Echo strNewString

En d'autres termes, voyons si nous pouvons faire quelque chose d'intéressant avec les expressions régulières, que nous ne pouvons pas faire avec la fonction Replace de VBScript.

Personne n'a d'idée ? Bon, en voici une. Nous autres scripteurs finissons souvent par devoir copier du texte d'un type de document vers un autre. Cela fonctionne parfois assez bien, mais parfois non. Lorsque cela ne fonctionne pas, nous nous retrouvons souvent avec des problèmes bizarres d'espacement des mots, des problèmes qui se traduisent par un texte ressemblant au texte ci-dessous :

Myer Ken, Vice President, Sales and Services

Aïe, regardez tous ces espaces superflus ! Dans un cas comme celui-ci, la fonction Replace offre une utilisation limitée. Pourquoi ? Eh bien, nous avons en apparence un nombre aléatoire d'espaces superflus : il peut y avoir 7 espaces entre les mots, ou 2, ou encore 6. Cela complique la résolution du problème à l'aide de Replace. Par exemple, si nous essayons de chercher 2 espaces consécutifs (en les remplaçant par un espace unique), nous obtenons ceci :

Myer Ken, Vice President, Sales and  Services

C'est mieux, mais pas beaucoup plus. Il existe une façon de faire, mais elle nécessite que nous recherchions un nombre arbitraire d'espaces (disons 39), que nous effectuions le remplacement, puis soustrayions 1 du nombre de départ, recherchions 38 espaces, effectuions le remplacement, etc., etc. Autre solution, nous pourrions utiliser ce script d'expressions régulières beaucoup plus simple (et beaucoup plus fiable) :

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = " {2,}"

strSearchString = _
"Myer Ken, Vice President, Sales and Services"
strNewString = objRegEx.Replace(strSearchString," ")

Wscript.Echo strNewString

L'élément clé de ce script (et l'élément clé de la plupart des scripts d'expressions régulières) est Pattern :

objRegEx.Pattern = " {2,}"

Nous recherchons ici 2 (ou plus) espaces consécutifs. Comment savons-nous que ce modèle (pattern) recherche 2 (ou plus) espaces ? Entre les guillemets doubles se trouve un espace unique suivi de cette construction : {2,}. Dans une syntaxe d'expressions régulières, cela correspond à la recherche de 2 instances consécutives du caractère précédent (en l'occurrence, un espace). Et s'il y avait 3, 4 ou 937 espaces consécutifs ? Pas de problème, ceux-ci seraient également pris en compte. (Si, pour une raison quelconque, nous voulions prendre en compte au moins 2 espaces mais pas plus de 8, nous utiliserions alors la syntaxe {2,8}, le 8 représentant le nombre maximal de correspondances).

En d'autres termes, chaque fois que nous trouverons 2 espaces ou plus, l'un après l'autre, nous nous emparerons de ces espaces consécutifs et les remplacerons par un espace unique. Quel sera l'effet sur notre valeur de chaîne initiale, celle qui comportait tous ces espaces ? Ceci :

Myer Ken, Vice President, Sales and Services

Vous voyez ? Les scripteurs peuvent vraiment améliorer les choses. Si seulement les gens du Louvre nous laissaient nous occuper de la Joconde.

Voici un scénario intéressant, et loin d'être rare. Supposez que votre entreprise possède un annuaire téléphonique et que tous les numéros de téléphone aient ce format :

555-123-4567

Maintenant, votre patron a décidé que tous les numéros de téléphone devaient avoir ce format :

(555) 123-4567

Comment pourriez-vous bien faire pour reformater tous ces numéros de téléphone ? Peut-être nous permettrez-vous l'audace de vous suggérer d'utiliser un script semblable à celui-ci :

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "(\d{3})-(\d{3})-(\d{4})"

strSearchString = "555-123-4567"
strNewString = objRegEx.Replace _
(strSearchString, "($1) $2-$3")

Wscript.Echo strNewString

Nous cherchons ici 3 chiffres (\d{3}) suivis d'un tiret, suivi de 3 chiffres supplémentaires et d'un tiret, suivis de 4 chiffres. En d'autres termes, nous recherchons ceci, où chaque X représente un nombre de 0 à 9 :

XXX-XXX-XXXX

Remarque : comment savions-nous que \d{3} indiquerait au script de rechercher trois nombres consécutifs ? Si je me souviens bien, nous l'avons lu quelque part. En fait, il s'agissait probablement du dernier chapitre (du reste choquant) du Da Vinci Code, ou de la référence du langage VBScript sur MSDN® en ligne (voir go.microsoft.com/fwlink/?LinkID=111387).

Il est vraiment pratique de pouvoir maintenant rechercher un numéro de téléphone arbitraire en utilisant des expressions régulières. Cependant, nous sommes toujours confrontés à un problème majeur ici. Après tout, nous ne pouvons pas remplacer ce numéro de téléphone arbitraire par un numéro de téléphone tout aussi arbitraire. Nous devons plutôt utiliser le même numéro de téléphone, simplement formaté un peu différemment. Comment donc faire cela ?

Hé bien, en utilisant le texte de remplacement suivant :

"($1) $2-$3"

$1, $2 et $3 sont des exemples d'expressions régulières de « référence arrière ». Une référence arrière est simplement une portion du texte trouvé qui peut être enregistrée et réutilisée par la suite. Dans ce script particulier, nous recherchons trois sous-correspondances :

  • une série de 3 chiffres ;
  • une série de 3 chiffres supplémentaires ;
  • une série de 4 chiffres.

Chacune de ces sous-correspondances est automatiquement affectée à une référence arrière : La première sous-correspondance est $1, la seconde est $2, et ainsi de suite, jusqu'à $9. En d'autres termes, dans ce script, les trois parties de notre numéro de téléphone sont automatiquement affectées aux références arrière illustrées à la figure 2.

Figure 2 Références arrière de numéro de téléphone

Partie de numéro de téléphone Référence arrière
555 $1
123 $2
4567 $3

Dans notre chaîne de remplacement, nous utilisons ces références arrière pour nous assurer que le numéro de téléphone correct est réutilisé. Notre texte de remplacement a simplement cette signification : Prendre la première référence arrière ($1) et la placer entre parenthèses. Laisser un espace, insérer ensuite la deuxième référence arrière ($2) suivie d'un tiret. Pour terminer, ajouter la troisième référence arrière ($3).

Qu'est-ce que tout cela va nous donner ? Cela va nous donner un numéro de téléphone semblable à ceci :

(555) 123-4567

Pas mal, pas mal du tout.

Voici une variation du script de numéro de téléphone. Supposons que votre organisation a installé un tout nouveau système téléphonique et que, dans le cadre du changement, tous vos numéros de téléphone doivent maintenant avoir le même préfixe. Alors que les numéros commençaient par 666, 777 ou 888, tous les numéros commenceront maintenant par 333. Pouvons-nous reformater les numéros de téléphone et modifier le préfixe de numéro de téléphone, tout ceci en même temps ? Bien sûr que nous le pouvons.

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "(\d{3})-(\d{3})-(\d{4})"

strSearchString = "555-123-4567"
strNewString = objRegEx.Replace _
(strSearchString,"($1) 333-$3")

Wscript.Echo strNewString

Vous voyez ce que nous venons de faire ici ? Nous avons simplement supprimé l'ancien préfixe (la référence arrière $2) dans notre texte de remplacement. À sa place, nous avons placé la valeur de préfixe maintenant standard et fixe, 333. Quel sera le numéro de téléphone 555-123-4567 après l'exécution de ce script modifié ? Il devrait très certainement ressembler à ceci :

(555) 333-4567

Voici une autre utilisation courante des références arrière. Supposons que nous avons une valeur de chaîne ressemblant à ceci :

Myer, Ken

Existe-t-il un moyen quelconque de renvoyer cette valeur et d'afficher le nom comme ceci :

Ken Myer

Nous aurions l'air stupides s'il n'en existait pas, n'est-ce pas ? Voici un script qui fait précisément cela :

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "(\S+), (\S+)"

strSearchString = "Myer, Ken"
strNewString = objRegEx.Replace _

strSearchString,"$2 $1")

Wscript.Echo strNewString

Dans ce script particulier, nous recherchons un mot (« (\S+) ») suivi d'une virgule, suivie d'un espace, suivi d'un autre mot. (En l'occurrence, nous utilisons « \S+ » pour représenter un mot) La construction \S+ signifie tout ensemble consécutif de caractères différents d'un espace. En d'autres termes, nous pourrions avoir une lettre, un chiffre, un symbole. En fait, nous pourrions avoir à peu près n'importe quoi sauf un espace, une tabulation ou un retour chariot-retour à la ligne. Comme vous pouvez le voir, nous nous attendons ici à trouver deux sous-correspondances : une représentant le nom ($1) et une représentant le prénom ($2). Grâce à ceci, nous pouvons afficher le nom d'utilisateur sous la forme Prénom Nom en utilisant cette syntaxe :

"$2 $1"

Où est la virgule ? Nous n'avions évidemment pas besoin d'elle et l'avons donc simplement rejetée.

Remarque : c'est drôle ; pour une raison ou une autre, nous avons également commencé à penser à l'éditeur de scripts. Hum.

Examinons une dernière chose avant de terminer pour aujourd'hui. (OK, avant de terminer pour ce mois-ci) Ceci n'est pas 100 % infaillible. Après tout, nous ne souhaitons pas qu'un article introductif tel que celui-ci soit trop compliqué. (Or, les expressions régulières ont la possibilité de devenir extrêmement compliquées) Néanmoins, voici un script qui, dans la plupart des cas, supprimera les zéros du début d'une valeur telle que 0000.34500044 :

Set objRegEx = CreateObject("VBScript.RegExp")

objRegEx.Global = True
objRegEx.Pattern = "\b0{1,}\."

strSearchString = _
"The final value was 0000.34500044."
strNewString = objRegEx.Replace _
strSearchString,".")

script.Echo strNewString

Comme d'habitude, la seule raison qui fait que cela fonctionne est le modèle : « \b0{1,}\ ». Nous commençons par rechercher une limite de mot (\b). Celle-ci permet de s'assurer que nous ne supprimons pas les zéros d'une valeur telle que 100.546. Nous recherchons ensuite un ou plusieurs zéros (« 0{1,} ») suivis d'un séparateur décimal (\.). Si le modèle est trouvé, nous remplaçons ces zéros (et le séparateur décimal) par un séparateur décimal simple (« . »). Si tout fonctionne conformément à notre plan, nous devrions obtenir la chaîne suivante :

The final value was .34500044.

Nous n'avons pas le temps d'en dire plus ce mois-ci. Avant de nous quitter, il est intéressant de noter que, avant même que sa peinture ait séché, la Joconde a été l'objet d'une controverse considérable. Qui est la femme mystérieuse ? Pourquoi sourit-elle comme cela ? Pourquoi n'a-t-elle pas de sourcils ? Plusieurs historiens d'art ont suggéré que la Joconde n'est même pas une femme, que le tableau est plutôt un autoportrait de Léonard De Vinci. (Si c'est vrai, il aurait vraiment dû chercher un autre tailleur) D'un autre côté, l'Unarius Educational Foundation est allée plus loin en déclarant que le tableau représentait en fait l'âme sœur de De Vinci dans un monde « de l'au-delà » et que cette âme sœur a guidé la main de De Vinci. Par une coïncidence remarquable, c'est exactement de cette façon que la rubrique Hé, vous le scripteur ! de ce mois-ci a été écrite.

Ce qui signifie que toutes les plaintes doivent être adressées à l'âme-sœur-du-scripteur-qui-écrit-cette-rubrique@l'autre-microsoft.com. Merci.

Les scripts embrouillés du Dr. Scripto

Le défi mensuel qui teste non seulement vos compétences de résolution des énigmes, mais également vos compétences d'écriture de scripts.

Mai 2008 : Script-doku

Ce mois-ci, nous allons jouer au Sudoku, mais avec une légère variante. Au lieu des chiffres 1 à 9 dans la grille, nous avons les lettres et des symboles qui forment ensemble le nom d'une applet de commande Windows PowerShell™. Dans la solution finale, l'une des lignes représentera le nom de l'applet de commande.

Remarque : si vous ne savez pas déjà jouer au Sudoku, il existe probablement plusieurs milliers de sites Web sur Internet qui vous donneront des instructions et nous n'allons donc pas les répéter ici, désolé.

ANSWER:

Les scripts embrouillés du Dr. Scripto

Réponse : Script-doku, mai 2008

Les scripteurs Microsoft travaillent pour (enfin, sont employés par) Microsoft. Lorsqu’ils ne sont pas en train de jouer au base-ball, d’entraîner une équipe ou de regarder un match (ou de se livrer à de multiples autres activités), ils dirigent le Script Center TechNet. Vous pouvez le vérifier vous-même sur www.scriptingguys.com.

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