Trucs et astuces
Ce document vise à aider à l’écriture et la lecture des scripts ; il est centré sur la programmation Xojo, et aborde :
– Les notions de base : variables et tableaux – boucles (FOR… et DO…).
– L’utilisation de ScriptEdit (3.5.0) – dont Debug pour tester de petits programmes et mettre au point un script.
– La notion de procédure et fonction.
Avertissement
Xojo a utilisé, et utilise encore en partie, la terminologie Visual Basic (V.B.), mais il tend maintenant à s’en affranchir. La compatibilité V.B. est néanmoins maintenue.
Pour assurer la comptabilité avec les anciennes versions de Filmotech, les scripts sont, pour l’instant, encore écrits avec la terminologie V.B.
Les variables
Toutes les variables doivent être déclarées par Dim nom as Type (ou avec la nouvelle terminologie Xojo Var nom as Type)
http://docs.xojo.com/Dim, http://docs.xojo.com/Var
Dim i, indice as Integer (ou Var i, indice as Integer) Dim chaine, texte as String (Var chaine, texte as String) Dim condition as Boolean (Var condition as Boolean) Dim x as Double (Var x as Double)
Noms
Pas de différence entre MAJUSCULES et minuscules (noms “insensibles à la case”); ainsi, Debut et debut représentent la même variable
Cette règle vaut également pour les noms réservés comme dim, integer, …
Les lettres accentuées sont autorisées dans Xojo. Mais attention : début et debut sont 2 variables différentes. L’habitude est cependant d’éviter les lettres accentuées.
Types
Principaux types utilisés dans les scripts : Integer, String, Boolean, Double
Integer
Cf. type entier. Type entier “historique” dit “signé” ; Correspond à Int32 sur les machines 32 bits (de -2 147 483 648 à 2 147 483647), codés sur 4 octets. Sur les machine 64 bits Integer correspond à Int64 (-9,223,372,036,854,775,808 à +9,223,372,036,854,775,807), codé sur 8 octets.
valeur par défaut = 0
String
Cf. Type chaine de caractères. Type chaine de caractères : suite de caractères tels lettres, chiffres, signes de ponctuation, etc. La longueur de la chaine n’est limitée que par la mémoire disponible.
Les valeurs doivent être mises entre guillemets. Si la chaine contient des guillemets, ils doivent être doublés.
chaine = "bonjour" texte = "il a dit ""bonjour"""
Valeur par défaut = “”
Remarque : Retour charriot (carriage return (CR)) est un caractère, de code 13. Pour le rendre actif dans une chaine il faut écrire CHR(13). Il est obligatoire entre chaque acteur ou réalisateur.
NB : Dans la documentation Xojo, à l’intitulé String, on a See Also qui renvoie aux opérateurs et fonctions relatifs aux chaines – comme Trim (supprime les espaces en début et fin d’une chaine), inStr (position d’une chaine dans une autre) ou NthFiled (extrait une sous-chaine d’une chaine, en fonction d’un séparateur).
A propos de NthField (NthField) et du fait que les “” doivent être doublés dans les constantes chaines, on a souvent à extraire une sous-chaine d’une chaine ou le séparateur est “ ; ex tiré du script SensCritique :
'soit par ex la ligne i : <a href="https://www.netflix.com/title/1089727" target="_blank" class="product-providers__item"> 'soit à en extraire l'adresse : https://www.netflix.com/title/1089727, en utilisant NthField et le séparateur " adresse = NthField(fmt_ValeurLigne(i), """" , 2 ) ' il y a 4 ", ce qui n'est pas à priori évident...
Boolean
Cf. Type booléen. Type booléen (en hommage au mathématicien George Boole), ne prend que 2 valeurs True (vrai) ou False (faux).
Valeur par défaut = False
dim condition as Boolean condition = left( fmt_ValeurLigne( i ) , 1 ) <> "<" AND trim(fmt_ValeurLigne( i )) <> ""
Remarque : 2 valeurs booléennes peuvent être reliées par OR (ou “inclusif”) ou AND.
- condition1 OR condition2 est VRAI si et seulement si l’une au moins des 2 conditions est VRAIE
- condition1 AND condition2 est VRAI si et seulement si les 2 conditions sont VRAIES.
Double
Cf.Type réel. Type réel double précision (±4.94065645841246544176568792868221372e-324 à ±1.79769313486231570814527423731704357e+308), codé sur 8 octets. A utiliser systématiquement (donc éviter le type Single, réel simple précision).
valeur par défaut = 0.0
Les tableaux
Cf. Tableaux (Arrays). Ensemble de valeurs numérotées à partir de 0, ayant toutes le même type.
dim acteurs, tableau() as string dim a, b, c as string a= "Fabrice Luchini" b= "Emmanuelle Seigner" c = "Yolande Moreau" tableau.append a tableau.append b tableau.append c fmt_DebugMsg(tableau(0)) 'affiche la première valeur du tableau dans la fenêtre de débogage acteurs = join(tableau, chr(13)) 'concatène les valeurs dans tableau dans une chaine ; chr13) comme séparateur fmt_AfficheMessage(acteurs) ' fmt_DebugMsg(acteurs) n'afficherait que la valeur de la chaine avant le 1er CR (pour fmt_DebugMsg il n'y a qu'une ligne disponible) redim tableau(-1) ' réinitialise le tableau acteurs = join(tableau, chr(13)) fmt_AfficheMessage(acteurs) 'donc chaine vide
Remarques :
- Les parenthèses (seules) après le nom de la variable tableau indique qu’il s’agit d’un tableau “dynamique”, cad dont le nombre d’éléments (la dimension) n’est pas précisé. Si l’on voulait déclarer un tableau de 10 valeurs de type chaine, on écrirait par ex : Dim MonTableau(9) as String (ne pas oublier que le premier élément a l’indice 0).
- Pour un tableau dynamique append (ou commande équivalente) est obligatoire ; tableau(0) = a provoquerait une erreur.
Tester un programme dans ScriptEdit
Il est possible de tester de petits programmes dans ScriptEdit pour voir comment se comportent tels ou tels éléments dans un futur script. A titre d’exemple on peut tester le programme ci-dessus sur les tableaux.
- Lancer ScriptEdit.
- Le programme doit être écrit dans Requete des titres (on peut copier / coller le programme ci-dessus, ou l’écrire…).
- Cliquer sur “Enregistrer” (donner un nom au programme)
- Exécuter : cliquer sur “Tester”, puis bouton “Recherche” – cliquer sur “OK” pour sortir.
La structure de boucle
C’est une notion qui, au début, peut être délicate…
Il y a deux principales structures de boucle : la boucle Pour (For…next) et la boucle Répéter (Do…loop).
Boucle Pour
syntaxe générale :
For i = debut to fin 'i de type integer [instructions] [Exit] 'facultatif [instructions)] Next
Les instructions entre For et Next seront exécutées n fois (n “passages” dans la boucle, n = fin – debut + 1). Lors du premier passage i aura la valeur debut; à la fin du premier passage le compteur i est augmenté d’une unité, etc.
En général debut = 1
La gestion du compteur est automatique
Tester la boucle Pour dans Scriptedit
NB : Pour fmt_DebugMsg et fmt_AfficheMessage, le paramètre peut être mis ou non entre parenthèses.
On peut donc écrire fmt_DebugMsg(“Bonjour”) ou fmt_DebugMsg “Bonjour”
Exemple
L’idée est de faire afficher la valeur du compteur i à chaque passage dans la boucle (avec un test, car on a un affichage particulier pour i = 1).
Cet exemple montre qu’on sort de la boucle avec i = n+ 1
' NB : str(nombre), fonction qui convertit un nombre en chaine de caractères ' str(i) obligatoire, car le paramètre de fmt_DebugMsg doit être de type chaine Dim i, n as Integer n= 5 For i = 1 to n if i = 1 then fmt_DebugMsg "premier passage dans la boucle" + " " + "i = " + str(i) else fmt_DebugMsg str(i) + " ème passage dans la boucle" + " " + "i = " + str(i) end if Next fmt_DebugMsg "i = " +str(i) + " en sortie de boucle"
NB : Une boucle Pour For i = debut to fin n’est pas exécutée si debut > fin (on sort alors de la boucle avec i = debut)
Boucle Répéter
syntaxe :
test en fin de boucle la boucle est exécutée au moins une fois | test en début de boucle la boucle ne sera pas exécutée si condition = true |
---|---|
Do [instructions] loop until condition | Do until condition [instructions] loop |
La différence entre une boucle Pour et une boucle Répéter tient essentiellement au fait que : dans une boucle Pour le nombre de passage(s) est déterminé à l’avance (géré par un compteur) – même si la boucle peut être interrompue par exit ; dans une boucle Répéter, il est indéterminé : on ne sait pas a priori au bout de combien de passage(s) condition sera vraie.
- NB : Il faut bien gérer la condition d’arrêt d’une boucle Répéter, car si elle n’est jamais vraie, la boucle sera “infinie”; le programme ne s’arrêtera pas et il faudra l’interrompre depuis le système d’exploitation.
Boucle Répéter dans Scriptedit – fmt_Recherche
Nous utiliserons la fonction fmt_Recherche(chaine_cherchée, Ligne_début, [ligne_fin], valeur exacte : True, sinon : False) ; la fonction renvoie -1 si aucune valeur trouvée ; fmt_IndexRecherche est la valeur de la ligne de chaine_cherchée.
Ex : script CinemaMontreal_fr.XML, Analyse des titres ; sur l’ensemble des lignes de la page HTML les titres sont délimités par <h3 class=’movietitle’> ; il faut exclure TV ; id est utilisé pour “analyse du détail”
dim searchString as String = "<h3 class='movietitle'>" index = 350 do until fmt_Recherche(searchString,index,true) = -1 id = NthField( fmt_ValeurLigne(fmt_IndexRecherche+1 ) , "'" , 2 ) if right(id,2) <> "tv" then date = str(val(right(id, 4))) if date < "1900" then date ="" titre = fmt_ValeurLigne( fmt_IndexRecherche+2 ) titre=replaceall(titre, "'", "'") titre = titre + " (" + date +")" fmt_MemoriseTitre (id , titre ) end if index = fmt_IndexRecherche+3 loop
Pour progresser dans la page HTML il faut naturellement augmenter la valeur de index à chaque passage dans la boucle Do (ici index = fmt_IndexRecherche+3)
Après le dernier film on ne trouve plus <h3 class=’movietitle’>, donc fmt_Recherche sera égal à -1.
Notion de procédure
Plutôt que d’écrire toutes les instructions de manière séquentielle, on en regroupe certaines dans des “procédures” pour accomplir des tâches spécifiques, par ex : recherche des notes, des acteurs, etc.
Sub Nom_Procedure(). ‘il peut y avoir des paramètres
[déclarations variables] instructions
End Sub
Les variables déclarées sont locales à la procédure ; si elles ont le même nom que certaines du programme “principal” ou “appelant”, elles prennent le pas sur les variables de même nom de ce programme.
Les variables du programme appelant (de noms différents) peuvent être utilisées dans la procédure.
Procédure dans ScriptEdit, Analyse du détail
Dans SensCritique, on prend des informations dans la page d’accueil des films, mais aussi dans la page Casting.
Les deux sont analysées par ScriptEdit dans Analyse du détail, ce qui oblige à avoir 2 procédures : une Film (Sub Film()…) pour la page d’accueil et une Casting (Sub casting ()…) (pour les acteurs, rôles,…).
Pour passer de l’une à l’autre on utilise fmt_RequeteDetailSuite(“get”, adresse_page, fmt_parametreDetail)
fmt_parametreDetail = ”“ par défaut
if fmt_parametreDetail = "" then dim chaine as string dim note as boolean = fmt_valeur("InclureNotes") = "OUI" film if note then Snotes 'Snotes : procédure de traitement des notes chaine = fmt_IdentifiantDetail + "/details" fmt_RequeteDetailSuite("get", chaine, "details") 'relance analyse du détail elseif fmt_parametreDetail = "details" then casting end if
Pour exécuter une procédure, il suffit de mettre son nom dans le “code” (film, casting, Snotes – sans parenthèses dans la mesure où il n’y a pas de paramètre) (après son exécution le programme continue séquentiellement)
Les procédures peuvent être écrites n’importe où dans le code. Une procédure peut en appeler une autre.
NB : If note est bien sûr équivalent à If note = true (mais ce serait redondant car on teste toujours après If si la condition est vraie) ;
If note = false peut s’écrire If Not note.
Procédure, paramètres
Exemple d’un script perso Unifrance : mettre en clair des lettres accentuées (qui sont codées dans la page HTML)
sub accents(byref P as string) P = replaceall(P, "ï", "ï") P = replaceall(P, "’", "'") P = replaceall(P, "ñ", "ñ") P = replaceall(P, "í", "í") P = replaceall(P, "ü", "ü") P = replaceall(P, "á", "á") P = replaceall(P, "ÿ", "ÿ") P = replaceall(P, "œ", "œ") P = replaceall(P, "ø", "ø") end sub
Procédure qui sera appelée pour titre, realisateurs : accents(titre), accents(realisateurs)
Pourquoi byref ?
Parce que sans Byref (“passage paramètre par valeur” : passage par défaut), P serait exclusivement local à la procédure.
Or on veut qu’il affecte la valeur du paramètre appelant (titre, realisateur, …) : il doit partager la même adresse mémoire que lui, la même “référence”. Byref : passage de paramètre par “référence”
NB : il y a une procédure similaire dans le script DVDEmpire_BR_DVD.XML
Fonctions
Une fonction est une procédure qui renvoie une valeur d’un type donné.
Reprenons l’exemple de la procédure accents ci-dessus, mais écrit sous forme de fonction Faccents.
function Faccents(P as string) as string P = replaceall(P, "ï", "ï") P = replaceall(P, "’", "'") P = replaceall(P, "ñ", "ñ") P = replaceall(P, "í", "í") P = replaceall(P, "ü", "ü") P = replaceall(P, "á", "á") P = replaceall(P, "ÿ", "ÿ") P = replaceall(P, "œ", "œ") P = replaceall(P, "ø", "ø") return P 'P est la valeur renvoyée par la fonction end function
Il suffit d’écrire : titre = Faccents(titre) ou realisateur = Faccents(realisateur)
(P est naturellement transmis par valeur)
Cases à cocher, boutons d’option
Exemple SensCritique :
Tester inclure les notes et inclure les rôles : (on peut utiliser des booléens)
dim character as boolean = fmt_valeur(“InclureRoles”) = “OUI”
dim note as boolean = (fmt_valeur(“InclureNotes”) = “OUI ”) ‘ les parenthèses ne sont pas obligatoires
Tester les boutons d’option (un seul suffit dans la mesure où il n’y en a que 2)
dim choixTitre as boolean = fmt_Valeur(“RadioBouton”) = “Titre”