Hé, vous le scripteur !Restez connecté à votre grille-pain

Les scripteurs Microsoft

Téléchargement du code disponible ici : HeyScriptingGuy2008_09.exe(150 Ko)

S'il est possible de résumer notre monde moderne, c'est bien avec ces deux mots : restez connecté. Grâce aux téléphones cellulaires, il n'est plus nécessaire que vous soyez chez vous pour que les gens vous appellent : ils peuvent vous joindre où que vous vous trouviez, à tout moment du jour ou de la nuit. (Oh, comme c'est... agréable !) Grâce à l'informatique sans fil, il n'est plus nécessaire que vous soyez à votre bureau pour travailler : désormais, vous pouvez travailler à votre domicile, sur la plage, bref où que vous vous trouviez.

Une histoire vraie : les parents du scripteur sont récemment partis en vacances en camping, mais ils ont été forcés de vivre à la dure, exactement comme les grands explorateurs Lewis et Clark, lorsqu'ils ont eu des problèmes pour se connecter au réseau sans fil du terrain de camping. Heureusement, la télévision par satellite fonctionnait encore !

Et ce n'est qu'une partie de l'histoire. Les périphériques GPS vous permettent de savoir exactement où vous vous trouvez, à quelques mètres près. Et certains de ces appareils permettent également à d'autres personnes de savoir exactement où vous vous trouvez. (La vieille expression « vous pouvez courir mais vous ne pouvez pas vous cacher » n'a jamais était aussi vraie qu'à l'heure actuelle). S'il le voulait, le scripteur qui écrit cet article pourrait demander à son compte-chèques de l'appeler à chaque fois qu'un chèque est débité ou à sa voiture de lui envoyer des rapports d'état mensuels par message électronique. Et comme si ça ne suffisait pas, le grille-pain a proposé d'emmener promener le chien et d'arroser les plantes lorsqu'il part en vacances.

Bon, d'accord, cette dernière partie n'est peut-être pas vraie, pas encore du moins. Mais s'il le voulait, le scripteur pourrait acheter un grille-pain doté de fonctionnalités Internet. Il pourrait ensuite appeler son grille-pain en rentrant chez lui et être accueilli par du pain grillé tout chaud lorsqu'il franchirait le pas de sa porte. Pour être honnête, nous ne voyons pas pourquoi vous voudriez être accueilli par du pain grillé tout chaud lorsque vous franchissez le pas de votre porte. Mais si cela vous tente...

Bien sûr, si l'objectif de tout un chacun est de rester connecté, il n'est pas surprenant que les scripteurs, qui ne sont pas esclaves des tendances, vous poussent à vous déconnecter davantage. Cela signifie-t-il que les scripteurs vous recommandent de jeter votre téléphone cellulaire ou votre ordinateur portable ? Non, même les scripteurs sont plus intelligents que cela. Cependant, ils plaident pour que vous ajoutiez des jeux d'enregistrement déconnectés à votre arsenal de scripts. Mais si vous voulez jeter votre téléphone cellulaire ou votre ordinateur portable, et bien, nous ne vous en empêcherons pas.

Remarque Selon une étude réalisée par Harris Interactive, 43 % des Américains ont utilisé un ordinateur portable en vacances pour consulter et envoyer des messages électroniques en rapport avec leur travail. Et plus de 50 % des Américains utilisent leur téléphone cellulaire en vacances pour consulter leurs messages électroniques et/ou leur messagerie vocale. Et cela n'inclut pas les 40 % d'Américains qui ne prennent pas de vacances sur une année.

Il va sans dire que de nombreuses personnes seraient ravies d'ajouter des jeux d'enregistrements déconnectés à leur arsenal de scripts, à ce détail près : elles n'ont pas la moindre idée de ce qu'est un jeu d'enregistrements déconnecté. Hé bien, au cas où vous ne seriez pas familiarisé avec le concept, un jeu d'enregistrements déconnecté est (plus ou moins) une table de base de données qui n'est pas liée à une véritable base de données. Au lieu de cela, elle est créée par un script, elle existe uniquement en mémoire et elle disparaît à la fin du script. En d'autres termes, un jeu d'enregistrements déconnecté est une structure de données constituée qui n'existe que pendant quelques minutes puis disparaît, emportant ses données avec elle. Woaw, bravo les scripteurs, ça semble vraiment utile ! Merci de votre aide !

Bon, d'accord : les jeux d'enregistrement déconnectés ne semblent pas terriblement passionnants. Et à la vérité, ils ne le sont pas. Mais ils peuvent être extrêmement utiles. Comme les auteurs de VBScript expérimentés ne le savent que trop bien, VBScript n'offre pas exactement les meilleures fonctionnalités de tri de données au monde. (Pas à moins que vous ne considériez l'absence de fonctionnalités de tri de données comme les meilleures fonctionnalités de tri de données au monde). De même, la capacité de VBScript à traiter de grandes séries de données est limitée, au mieux. Outre l'objet Dictionary (qui vous limite à travailler avec des articles qui ont, au plus, deux propriétés) ou le tableau (qui est principalement limité aux listes de données à propriété unique), hé bien... il n'y a rien d'autre.

Le jeu d'enregistrements déconnecté vous permet de gérer ces deux problèmes (et d'autres encore). Vous devez trier vos données, notamment des données à propriétés multiples ? Aucun problème ; comme nous l'avons dit, un jeu d'enregistrements déconnecté est l'équivalent virtuel d'une table de base de données et il n'y a rien de plus facile à faire que trier une table de base de données. (D'accord, si vous voulez être pointilleux, on peut considérer que ne pas trier une table de base de données est plus facile que trier une table de base de données). Ou peut-être disposez-vous d'une grande série d'éléments, des éléments avec des propriétés multiples, dont vous devez assurer le suivi ? Aucun problème. Avons-nous dit qu'un jeu d'enregistrements déconnecté est l'équivalent virtuel d'une table de base de données ? Vous devez filtrer des informations ou rechercher des données avec une valeur spécifique ? Oh, si seulement il existait un moyen d'utiliser l'équivalent virtuel d'une table de base de données...

Voilà une remarque judicieuse : il est peut-être temps de vous montrer de quoi nous parlons. (En supposant que nous sachions de quoi nous parlons). Pour les débutants, disons que nous avons des statistiques de base-ball présentées à la figure 1, statistiques collectées sur le site Web MLB.com et stockées dans un fichier de valeurs séparées par des tabulations, C:\Scripts\Test.txt.

Figure 1 Statistiques stockées dans un fichier de valeurs séparées par des tabulations

Joueur Coups de circuit Points produits Moyenne
D Pedroia 4 28 .276
K Kouzmanoff 8 25 .269
J Francouer 7 35 .254
C Guzman 5 20 .299
F Sanchez 2 25 .238
I Suzuki 3 15 .287
J Hamilton 17 67 .329
I Kinsler 7 35 .309
M Ramirez 12 39 .295
A Gonzalez 17 55 .299

Tout cela est bien beau, mais supposons que nous voulions afficher cette liste de joueurs triée en fonction du nombre de coups de circuit qu'ils ont réalisés. Un jeu d'enregistrements déconnecté peut-il nous aider dans ce cas ? Nous allons très bientôt le savoir. Jetez à coup d'œil à la figure 2. Oui, il y a beaucoup de code, pas vrai ? Mais ne vous inquiétez pas. Comme vous le verrez bientôt, cela fait plus de bruit que de mal.

Figure 2 Un jeu d'enregistrements déconnecté

Const ForReading = 1
Const adVarChar = 200
Const MaxCharacters = 255
Const adDouble = 5

Set DataList = CreateObject("ADOR.Recordset")
DataList.Fields.Append "Player", _
  adVarChar, MaxCharacters
DataList.Fields.Append "HomeRuns", adDouble
DataList.Open

Set objFSO = _
  CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile _
  ("C:\Scripts\Test.txt", ForReading)

objFile.SkipLine

Do Until objFile.AtEndOfStream
    strStats = objFile.ReadLine
    arrStats = Split(strStats, vbTab)

    DataList.AddNew
    DataList("Player") = arrStats(0)
    DataList("HomeRuns") = arrStats(1)
    DataList.Update
Loop

objFile.Close

DataList.MoveFirst

Do Until DataList.EOF
    Wscript.Echo _
        DataList.Fields.Item("Player") & _
        vbTab & _
        DataList.Fields.Item("HomeRuns")
    DataList.MoveNext
Loop

Pour commencer, nous définissons quatre constantes :

  • ForReading. Nous utiliserons cette constante lorsque nous ouvrons et lisons le fichier texte.
  • adVarChar. Il s'agit d'une constante ADO standard pour créer un champ qui utilise le type de données Variant.
  • MaxCharacters. Il s'agit d'une constante ADO standard utilisée pour indiquer le nombre maximal de caractères (dans ce cas, 255) qu'un champ Variant peut contenir.
  • adDouble. Une dernière constante ADO, permettant de créer un champ qui utilise un type de données doubles (numériques).

Après avoir défini les constantes, nous avons ce bloc de code :

Set DataList = CreateObject _
    ("ADOR.Recordset")
DataList.Fields.Append "Player", _
    adVarChar, MaxCharacters
DataList.Fields.Append "HomeRuns", _
    adDouble
DataList.Open

C'est la partie du script dans laquelle nous configurons réellement notre jeu d'enregistrements déconnecté. Pour cela, la première chose à faire est de créer une instance de l'objet ADOR.Recordset ; inutile de dire que cela crée notre table de base de données virtuelle (c'est-à-dire, notre jeu d'enregistrements déconnecté).

Nous utilisons ensuite cette ligne de code (et la méthode Append) pour ajouter un nouveau champ au jeu d'enregistrements :

DataList.Fields.Append "Player", adVarChar, MaxCharacters

Comme vous pouvez le voir, il n'y a aucune fantaisie dans tout cela : nous appelons simplement la méthode Append suivie par trois paramètres :

  • Le nom du champ (Player).
  • Le type de données pour le champ (adVarChar).
  • Le nombre maximal de caractères pouvant être enregistrés dans le champ (MaxCharacters).

Après avoir ajouté le champ Player, nous pouvons ajouter un deuxième champ : HomeRuns (Coups de circuit), qui a un type de données numériques (adDouble). Une fois terminé, nous appelons la méthode Open pour déclarer notre jeu d'enregistrements ouvert et prêt à fonctionner.

Ensuite, nous créons une instance de Scripting.FileSystemObject et ouvrons le fichier C:\Scripts\Test.txt. Cette partie du script n'a en réalité rien à voir avec le jeu d'enregistrements déconnecté ; elle n'est là que parce que nous devons récupérer des données depuis un fichier texte. La première ligne du fichier texte contient nos informations d'en-tête :

Player     Home Runs     RBI        Average

Nous n'avons pas besoin de ces informations pour notre jeu d'enregistrement, donc la première chose à faire après avoir ouvert le fichier est d'appeler la méthode SkipLine pour ignorer la première ligne :

objFile.SkipLine

Maintenant que nous sommes passés à la première ligne comprenant réellement des données, nous configurons une boucle Do Until conçue pour nous permettre de lire le reste du fichier ligne par la ligne. Chaque fois que nous lisons une ligne du fichier, nous enregistrons cette valeur dans une variable nommée strLine, puis utilisons la fonction Split pour convertir cette ligne en un tableau de valeurs (en fractionnant la ligne chaque fois que nous rencontrons une tabulation) :

arrStats = Split(strStats, vbTab)

Il est vrai que c'est une présentation un peu rapide, mais nous pensons que, maintenant, la plupart d'entre vous êtes assez bons pour récupérer des informations depuis des fichiers texte. En résumé, pour le premier passage dans la boucle, le tableau, arrStats, contiendra les éléments de la figure 3.

Figure 3 Contenu du tableau

Numéro d'élément Nom d'élément
0 D Pedroia
1 4
2 28
3 .276

Maintenant, il est temps de s'amuser :

DataList.AddNew
DataList("Player") = arrStats(0)
DataList("HomeRuns") = arrStats(1)
DataList.Update

Nous ajoutons les informations pour le joueur 1 (D Pedroia) au jeu d'enregistrements déconnecté. Pour ajouter un enregistrement au jeu d'enregistrements, nous commençons par appeler la méthode AddNew : cela crée un nouvel enregistrement vierge avec lequel nous pouvons travailler. Nous utilisons les deux prochaines lignes de code pour attribuer des valeurs à deux champs du jeu d'enregistrements (Player et HomeRuns), puis nous appelons la méthode Update pour écrire officiellement cet enregistrement dans le jeu d'enregistrements. Puis de retour au sommet de la boucle, nous répétons le processus avec la ligne suivante, autrement dit le joueur suivant, dans le fichier texte. Vous voyez ? Il y a peut-être beaucoup de code ici, mais c'est globalement assez simple.

Alors, que se passe-t-il après que tous les joueurs ont été ajoutés au jeu d'enregistrements ? Après avoir fermé le fichier texte, nous exécutons ce bloc de code :

DataList.MoveFirst

Do Until DataList.EOF
  Wscript.Echo _
    DataList.Fields.Item("Player") & _
    vbTab & _
    DataList.Fields.Item("HomeRuns")
  DataList.MoveNext
Loop

À la ligne 1, nous utilisons la méthode MoveFirst pour positionner le curseur au début du jeu d'enregistrements ; si nous ne faisons pas cela, nous courons le risque d'afficher seulement une partie des données dans le jeu d'enregistrements. Nous configurons ensuite une boucle Do Until qui continuera jusqu'à ce que nous n'ayons plus de données (c'est-à-dire, jusqu'à ce que la propriété EOF (fin de fichier) du jeu d'enregistrements soit True).

Dans cette boucle, nous nous limitons à renvoyer les valeurs des champs Player et HomeRuns (notez la syntaxe quelque peu curieuse utilisée pour indiquer un champ précis : DataList.Fields.Item("Player"). Nous appelons ensuite simplement la méthode MoveNext pour passer à l'enregistrement suivant dans le jeu d'enregistrements.

Inutile de le dire, c'était vraiment facile. Une fois que tout est terminé, nous devrions obtenir ce qui suit :

D Pedroia       4
K Kouzmanoff    8
J Francouer     7
C Guzman        5
F Sanchez       2
I Suzuki        3
J Hamilton      17
I Kinsler       7
M Ramirez       12
A Gonzalez      17

Comme vous pouvez le voir, c'est... bon, en fait, ce n'est pas si bien que ça, pas vrai ? Certes, nous avons le nom des joueurs et les totaux des coups de circuits, mais ces derniers ne sont pas classés dans l'ordre. Saperlipopette, pourquoi le jeu d'enregistrements déconnecté ne trie-t-il pas nos données pour nous ?

Pour une bonne raison : nous n'avons pas dit au jeu d'enregistrements sur quel champ nous voulions baser le tri. Mais c'est très simple à corriger : il suffit de modifier le script pour ajouter les informations de tri avant d'appeler la méthode MoveFirst. Autrement dit, cette partie du script doit ressembler à cela :

DataList.Sort = "HomeRuns"
DataList.MoveFirst

Évidemment, il n'y a aucune astuce. Nous attribuons simplement le champ HomeRuns à la propriété Sort. Jetons maintenant un coup d'œil au résultat obtenu en exécutant le script :

F Sanchez       2
I Suzuki        3
D Pedroia       4
C Guzman        5
J Francouer     7
I Kinsler       7
K Kouzmanoff    8
M Ramirez       12
J Hamilton      17
A Gonzalez      17

C'est bien mieux. Oui, à l'exception d'une chose : généralement les totaux des coups de circuit sont classés dans l'ordre décroissant, le joueur ayant réalisé le plus de coups de circuit apparaissant en premier. Est-il possible de trier un jeu d'enregistrements déconnecté dans l'ordre décroissant ?

Bien sûr. Il suffit d'utiliser l'utile paramètre DESC, comme cela :

DataList.Sort = "HomeRuns DESC"

Et que fait le paramètre DESC pour nous ? Vous l'avez deviné :

A Gonzalez      17
J Hamilton      17
M Ramirez       12
K Kouzmanoff    8
I Kinsler       7
J Francouer     7
C Guzman        5
D Pedroia       4
I Suzuki        3
F Sanchez       2

Au passage, il est parfaitement possible d'effectuer un tri basé sur plusieurs propriétés ; il suffit d'attribuer chacune de ces propriétés à l'ordre du tri. Par exemple, supposons que vous vouliez baser le tri en premier sur les coups de circuit puis sur les points produits. Aucun problème, cette commande est là pour ça :

DataList.Sort = "HomeRuns DESC, RBI DESC"

Essayez et vous vous en rendrez compte vous-même. Ce n'est pas aussi amusant que consulter ses messages électroniques en vacances, mais c'est pas mal.

Remarque N'oubliez pas que vous ne pouvez pas baser le tri sur un champ qui n'a pas été ajouté au jeu d'enregistrements. Qu’est-ce que cela signifie ? Avant d'ajouter une propriété telle que RBI à l'instruction de tri, vous devez ajouter ces lignes à votre script aux emplacements appropriés :

DataList.Fields.Append "RBI", adDouble

DataList("RBI") = arrStats(2)

Et si vous voulez voir le résultat, vous devez également modifier votre instruction Wscript.Echo :

Wscript.Echo _
  DataList.Fields.Item("Player") & _
  vbTab & _
  DataList.Fields.Item("HomeRuns") & _
  vbTab & DataList.Fields.Item("RBI")

Voyons, que pouvons-nous faire d'autre avec les jeux d'enregistrements déconnectés ? Je pense bien à quelque chose. Supposons que nous récupérions toutes les informations pour tous les joueurs puis triions ces données en fonction de la moyenne à la batte. (Entre autres choses, cela signifie que nous devons modifier notre script original pour créer des champs nommés RBI (points produits) et BattingAverage (moyenne à la batte). Voici à quoi ressemble le résultat :

J Hamilton      17      67      0.329
I Kinsler       7       35      0.309
A Gonzalez      17      55      0.304
C Guzman        5       20      0.299
M Ramirez       12      39      0.295
I Suzuki        3       15      0.287
D Pedroia       4       28      0.276
K Kouzmanoff    8       25      0.269
J Francouer     7       35      0.254
F Sanchez       2       25      0.238

C'est bien, mais que se passe-t-il si nous voulons juste la liste des joueurs avec un score minimal de 0,300 ? Comment pouvons-nous limiter les données affichées aux joueurs qui respectent certains critères spécifiés ? Et bien, une façon de procéder consiste à attribuer un filtre au jeu d'enregistrements :

DataList.Filter = "BattingAverage >= .300"

Un filtre de jeu d'enregistrements sert globalement à la même chose qu'une requête de base de données : il fournit un mécanisme pour limiter les données renvoyées à un sous-ensemble de tous les enregistrements du jeu d'enregistrements. Dans ce cas, nous demandons simplement au filtre d'éliminer tous les enregistrements sauf ceux dont le champ BattingAverage a une valeur supérieure ou égale à 0,300. Et vous savez quoi ? Le filtre fera exactement ce que nous lui demandons :

J Hamilton      17      67      0.329
I Kinsler       7       35      0.309
A Gonzalez      17      55      0.304

Si seulement nos gosses se comportaient de la même façon...

À propos, vous pouvez utiliser plusieurs critères dans un filtre unique. Par exemple, cette commande limite les données renvoyées aux enregistrements dans lesquels le champ BattingAverage est supérieur ou égal à 0,300 et le champ HomeRuns est supérieur à 10 :

DataList.Filter = _
  "BattingAverage >= .300 AND HomeRuns > 10"

En revanche, ce filtre limite les données aux enregistrements dans lesquels le champ BattingAverage est supérieur ou égal à 0,300 ou le champ HomeRuns supérieur à 10 :

DataList.Filter = "BattingAverage >= .300 OR HomeRuns > 10"

Essayez les deux solutions et vous verrez la différence. Et puis flûte : juste pour le plaisir, voici un autre filtre que vous pouvez essayer :

DataList.Filter = "Player LIKE 'I*'"

Il se trouve que vous pouvez également utiliser des caractères génériques dans vos filtres. Pour cela, utilisez l'opérateur LIKE (par opposition au signe égal) puis l'astérisque comme vous le feriez en exécutant une commande MS-DOS® comme dir C:\Scripts\*.txt. Dans l'exemple précédent, nous devrions obtenir une liste de joueurs dont le nom commence par la lettre I. En effet, la syntaxe employée dit « Montre-moi une liste de tous les enregistrements dans lesquels la valeur du champ Player commence par I puis est suivie de n'importe quoi ». Essayez, enfin vous connaissez la routine maintenant.

À propos, vous n'êtes pas non plus bloqué avec les moyennes à la batte comme 0,309. (En anglais, généralement, les moyennes à la batte sont exprimées sans le 0, autrement dit .309, par exemple). Mais c'est parfait. Vous pouvez simplement utiliser la fonction FormatNumber pour formater la moyenne à la batte comme vous le voulez :

FormatNumber (DataList.Fields.Item("BattingAverage"), 3, 0)

Il vous suffit d'inclure cette fonction dans votre instruction Wscript.Echo lorsque vous affichez le nombre (ou bien, vous pouvez attribuer le résultat à une variable et mettre la variable dans votre instruction Echo) :

Wscript.Echo _
  DataList.Fields.Item("Player") & _
  vbTab & _
  DataList.Fields.Item("HomeRuns") & _
  vbTab & DataList.Fields.Item("RBI") & _
  vbTab & _
  FormatNumber _
  (DataList.Fields.Item("BattingAverage"), _
   3, 0)

Amusant, pas vrai ?

Malheureusement, il semble que nous n'ayons plus assez de temps ce mois-ci. En résumé, nous voudrions juste dire que..., désolé le téléphone sonne.

De toute façon, nous voulions préciser que..., oh, super, maintenant le téléphone portable sonne. Et nous venons de recevoir un message électronique du grille-pain. Important : notre pain grillé tout chaud est prêt. Voulons-nous du beurre ou de la confiture ? Je dois y aller, mais nous vous verrons le mois prochain !

Les scripts embrouillés du Dr. Scripto

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

Septembre 2008 : Recherche de script

Voici une recherche de mot simple (ou peut-être pas si simple). Recherchez toutes les fonctions et instructions VBScript de la liste. Mais attention au piège : les lettres restantes forment un mot masqué qui s'avère être, vous l'avez deviné, une applet de commande Windows PowerShell™ !

Liste des mots : Abs, Array, Atn, CCur, CLng, CInt, DateValue, Day, Dim, Else, Exp, Fix, InStr, IsEmpty, IsObject, Join, Len, Log, Loop, LTrim, Mid, Month, MsgBox, Now, Oct, Replace, Set, Sin, Space, Split, Sqr, StrComp, String, Timer, TimeValue, WeekdayName.

fig08.gif

RÉPONSE :

Les scripts embrouillés du Dr. Scripto

Réponse : Septembre 2008 : Recherche de script

fig08.gif

Les scripteurs 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.