5.6 expressions régulières méthodes |
See You Why? |
De quoi s'agit-il encore ? Encore une nouveauté inventée par ces concepteurs du site CUY ?
Nous avions signalé dans la séquence précédente que les expressions régulières permettaient d'effectuer des recherches complexes dans des chaînes de caractères.
Cela reste vrai et nous ne pensions pas au départ vous parler des méthodes applicables à ces expressions régulières... mais nous avons changé d'avis.
Pourquoi pensions-nous ne pas en parler ?
Premièrement, parce que les "expressions régulières" sont des objets JavaScript et que nous ne comptions vous parler des objets qu'à partir du chapitre 23 de ce tutoriel.
Deuxièmement, parce que les méthodes sont considérées comme des fonctions applicables à certains objets... et nous n'aborderons les fonctions qu'à partir du chapitre suivant...
Troisièmement, parce qu'aborder un sujet difficile en début de formation JS ne nous semblait pas être le meilleur choix.
Trop tôt donc pour vous parler de méthodes, fonctions applicables à des objets...
Pourquoi en parler maintenant alors ?
Principalement, parce que si l'on touche à ce sujet assez difficile des "expressions régulières" on ne peut pas faire sans introduire des fonctions qui sont indissociables des expressions régulières ni sans les avoir un peu détaillées.
Nous avons cependant déjà montré quelques unes de ces méthodes dans la séquence précédente, mais sans avoir attirer l'attention. Un petit rappel... :
Dans notre premier exemple, nous avions noté :
var expr2 = new RegExp("a","g");
var rep1 = ma_variable.replace(expr2," ");
et vous n'avez pas été étonné de voir tous les 'a' de la variable ma_variable être remplacés par une espace, sans exiger d'explications complémentaires.
Dans les exemples suivants, nous avons essentiellement fait appel à cette méthode replace()
qui nous paraissait assez facile pour illustrer nos propos.
Cependant, lorsque dans la même séquence, nous avons donné quelques exemples d'utilisation, nous avons par exemple utilisé le script suivant pour rechercher la présence d'un mot dans un texte :
var exp=new RegExp(mot,"g");
if ( exp.test(f.texte.value) ) {...
et aucune question sur ce test() ?
Dans un autre exemple qui consistait à décomposer une chaine de caractères en plusieurs éléments d'un tableau, je vous ai rapidement suggéré ce qu'était un tableau ou array en JS, mais vous ne vous êtes pas étonné de cette partie du script :
var mon_tableau= mon_texte.split(/\s/g);
il est donc temps de vous présenter ces quelques méthodes fréquemment utilisées avec des "expressions régulières".
Voici donc quelques informations complémentaires relatives aux méthodes compile(), exec(), match(), replace(), search(), split(), test() :
compile() | Pour modifier le contenu d'une variable 'expression régulière' déjà créée. Évite de créer de nouveaux objets de type RegExp. Ex: |
"i" | pour rechercher le motif en ignorant, sans tenir compte de la casse (capitale ou bas de casse, improprement [majuscule / minuscule]) |
"g" | pour rechercher le motif de façon globale (toutes les occurences sur toute la chaine sur laquelle s'applique la fonction) |
"gi" | pour rechercher le motif globalement et ignorant la casse |
chaine1.test(chaine2) |
Pour découvrir si chaine1 est présente dans chaine2. |
Cette méthode, à savoir l'expression régulière compile() tombe en désuétude en JavaScript, mais est encore parfois utilisée. Par contre, le langage Python l'utilise beaucoup.
Comme annoncé ci-dessus, cette méthode permet de modifier le contenu d'une expression régulière déjà utilisée dans le programme.
Quelle en est l'utilité ? Assez faible nous semble-t-il...
certains disent qu'il s'agit d'économiser la mémoire centrale de l'ordi sur lequel tourne le script, mais il me semble qu'aujourd'hui, la RAM des ordinateurs soit suffisamment importante que pour ne plus devoir souffrir de cet inconvénient ;
d'autres affirment que, si dans un script on fait appel à plusieurs expressions régulières, il peut être préférable d'utiliser un seul objet. Les expressions régulières successives qui lui seront affectées seront tout d'abort fournies sous forme de chaîne qu'il faudra donc transformer en un objet de type RegExp. Cette transformation d'une chaîne de caractères vers une expression régulière est opérée par la méthode compile(<chaîne> [,<attributs>]). C'est ce que nous allons illustrer ci-dessous.
Rappelez-vous notre premier exemple, il s'agissait de remplacer la lettre 'a' par un espacement. Imaginez-vous maintenant que vous soyez dans l'obligation de convertir tout message et pour chacun des 42 caractères de notre alphabet de la langue française (et oui, 26 lettres de l'alphabet, 2 ligatures œ et æ auxquelles il faut ajouter tous nos caractères accentués). Si on se limite aux bas de casse (minuscules), faudrait-il utiliser 42 objets différents pour coder l'expression ? Évidemment non, c'est un cas où la redéfinition d'un objet unique peut s'avérer intéressante. Cet exemple ferait appel aux boucles que nous ne verrons qu'à partir du chapitre 19 et aux tableaux que nous ne verrons qu'à partir du chapitre 26... évitons donc...
Montrons par un exemple plus simple, la possibilité de redéfinir une expression régulière :
la plus simple est celle qui recherche un seul caractère. Ainsi, pour rechercher le caractère 'a' ... dans l'expression régulière, on a noté "a" entre guillemets ou /a/ entre slashs[1].
Ainsi, on a écrit :
var ma_variable = "Premiers pas de programmation en JavaScript"; var expr2 = new RegExp("a","g"); //on aurait pu écrire var expr2 = /a/g; var rep2 = ma_variable.replace(expr2," "); document.write(rep2); // affichera 'Premiers p s de progr mm tion en J v Script' car tous les 'a' sont trouvés et remplacés
Notre variable expr2 était un objet de type "expression régulière"... si nous voulons maintenant redéfinir cette expression, sans en créer une nouvelle pour remplacer les "p" en "a", sans oublier que cette lettre 'p' apparait aussi en capitale on pourrait écrire à la suite :
expr2 = /p/gi; expr2.compile(expr2); var rep3 = rep2.replace(expr2,"a"); document.write(rep3); // affichera 'aremiers a s de arogr mm tion en J v Scriat' car tous les 'p' sont trouvés et remplacés
et l'on constate que l'expression régulière expr2 a été 'recompilée' et appliquée à la variable rep2 pour obtenir la variable rep3. Tous les 'p', qu'ils soient en capitales[2] ou en bas de casse ont été remplacés par un 'a' en bas de casse.
Le lecteur attentif pourrait formuler plusieurs reproches :
Exemple
|
À peine plus difficile, en JS, l'expression régulière qui recherche non plus un seul caractère, mais une chaine de caractères. Ainsi, pour rechercher la chaine de caractères 'pr' ... dans l'expression régulière, on notera "pr" entre guillemets.
Ainsi, en écrivant :
var ma_variable = "Premiers pas de programmation en JavaScript"; var expr = new RegExp("pr"); var expr2 = new RegExp("pr","gi"); var rep1 = ma_variable.replace(expr,"xx"); alert(rep1); // affichera 'Premiers pas de xxogrammation en JavaScript' car 'pr' en bas de casse est trouvé et remplacé en 16e place var rep2 = ma_variable.replace(expr2,"xx"); document.write(rep2); // affichera 'xxemiers pas de xxogrammation en JavaScript' car tous les 'pr', sans tenir compte de la casse sont trouvés et remplacés
Exemple
|
Un pas de plus, en JS, une expression régulière qui recherche non plus une chaine de caractères mais un choix de chaines de caractères. Ainsi, pour rechercher l'une des chaines de caractères 'pr' ou 'at'... dans l'expression régulière, on notera "pr|at" entre guillemets.
Mais quel est ce caractère bizarre '|' ? C'est un caractère, souvent dénommé 'pipe' (prononcé à l'anglaise 'païpe' qui s'obtient en appuyant simultanément sur la touche 'AltGr' et le '&' [même touche que le 1 sur les claviers belges]
Ainsi, en écrivant :
var ma_variable = "Premiers pas de programmation en JavaScript"; var expr = new RegExp("pr|at"); var expr2 = new RegExp("pr|at","gi"); var rep1 = ma_variable.replace(expr,"xx"); alert(rep1); // affichera 'Premiers pas de xxogrammation en JavaScript' car le premier 'pr' en bas de casse est trouvé et remplacé en 16e place var rep2 = ma_variable.replace(expr2,"xx"); document.write(rep2); // affichera 'xxemiers pas de xxogrammxxion en JavaScript' car tous les 'pr' ou 'at', sans tenir compte de la casse sont trouvés et remplacés
Exemple
|
Encore un pas de plus, en JS... on parlera bientôt chinois ou arabe... une expression régulière qui recherche non plus un choix de chaines de caractères, mais des portions de chaines au choix. Ainsi, pour rechercher l'une des chaines de caractères 'stop', 'pop' ou 'hop'... après avoir observé qu'elles se terminent toutes par 'op' mais commencent soit par 'st', 'p' ou 'h', dans l'expression régulière, on pourrait noter"stop|pop|hop" entre guillemets, mais on va préférer la notation du choix entre parenthèses (pour une partie de l'expression), suivi de la partie fixe de la chaine, le tout entre parenthèses.
Ainsi, en écrivant :
var ma_variable = "Halte ! Stop ! Quelle est cette populace qui fait tant de shopping ?"; var expr = new RegExp("(st|p|h)op"); var expr2 = new RegExp("(st|p|h)op","gi"); var rep1 = ma_variable.replace(expr,"22"); alert(rep1); // affichera 'Halte ! Stop ! Quelle est cette 22ulace qui fait tant de shopping ?' car le premier 'pop' en bas de casse est trouvé et remplacé var rep2 = ma_variable.replace(expr2,"3"); document.write(rep2); // affichera 'Halte ! 3 ! Quelle est cette 3ulace qui fait tant de s3ping ?' car tous les 'pop', 'stop' ou 'hop', sans tenir compte de la casse sont trouvés et remplacés
Exemple
|
On n'est pas encore au bord du précipice, faisons donc un pas de plus, en JS... une expression régulière qui recherche non plus un choix de chaines de caractères, mais des portions de chaines au choix. Ainsi, pour rechercher l'une des chaines de caractères 'eae', 'ebe' ou 'ece'... après avoir observé qu'elles se composent de deux 'e' séparés par un caractère quelconque, dans l'expression régulière, on pourrait noter"e.e" entre guillemets, Le 'point' fait office de joker et peut remplacer n'importe quel caractère, y compris virgule, point d'interrogation et autres (mais pas un 'retour à la ligne').
Attention, il ne remplace qu'un seul caractère... pour les vieux routiers du DOS, c'est l'équivalent du '?' et non pas de l' '*'.
'..' signifierait deux caractères quelconques.
Ainsi, en écrivant :
var ma_variable = "Halte ! Stop ! Quelle est cette populace qui fait tant de shopping ?"; var expr = new RegExp("e..e"); var expr2 = new RegExp("e..e","gi"); var rep1 = ma_variable.replace(expr,"4"); alert(rep1); // affichera 'Halte ! Stop ! Qu4 est cette populace qui fait tant de shopping ?' car le premier 'elle' en bas de casse est trouvé et remplacé var rep2 = ma_variable.replace(expr2,"4"); document.write(rep2); // affichera 'Halte ! Stop ! Qu4 est c4 populace qui fait tant de shopping ?' car tous les 'elle', 'ette' sans tenir compte de la casse sont trouvés et remplacés
Exemple
|
Toujours plus, en JS... une expression régulière qui recherche non plus des choix de chaines de caractères, mais un début ou une fin de chaine. Ainsi, pour rechercher si une chaine de caractères commence bien par 'ha', dans l'expression régulière, on notera simplement "^ha" entre guillemets ; pour rechercher si une chaine de caractères se termine bien par '?', dans l'expression régulière, on notera simplement "?$" entre guillemets.
Le 'caret' ou '^', placé devant une chaine indique que la chaine doit commencer par la chaine qui suit ce caret (obtenu avec 'AltGr' sur la touche du 6) ;
le 'dollar' ou '$' qui suit une chaine indique que la chaine doit se terminer par cette chaine ;
le lecteur attentif aura remarqué que la clé "gi" ci-dessous n'a pas de sens, puisqu'il ne peut s'agir d'une recherche sur toute la chaine, mais uniquement sur la fin de la chaine ; la clé "i" seule suffisait et s'avèrerait nécessaire ici pour modifier le 'Ha' initial.
Ainsi, en écrivant :
var ma_variable = "Halte ! Stop ! Quelle est cette populace qui fait tant de shopping ?"; var expr = new RegExp("^ha"); var expr2 = new RegExp("?$","gi"); var rep1 = ma_variable.replace(expr,"4"); alert(rep1); // affichera 'Halte ! Stop ! Quelle est cette populace qui fait tant de shopping ?' car le premier 'Ha' n'est pas en bas de casse var rep2 = ma_variable.replace(expr2,"555"); document.write(rep2); // affichera 'Halte ! Stop ! Quelle est cette populace qui fait tant de shopping 555' car tous le '?' final, sans tenir compte de la casse est trouvé et remplacé
Exemple
|
Comme indiqué ci-dessus, la méthode test(), appliquée à une chaine1 va permettre de découvrir si chaine1 est présente dans chaine2.
La valeur renvoyée par cette méthode est une valeur booléenne true ou false.
Puisque cette méthode renvoie une valeur booléenne, on trouvera normal de voir cette méthode essentiellement utilisée dans des conditions IF que nous verrons plus tard au chapitre 14 et suivants.
Voici un exemple élémentaire:
var modele = new RegExp("e","g");
var texte = "Seuls les bons professeurs forment les bons autodidactes, disait Jean-François Revel";
var reponse = modele.test(texte);
alert(reponse);
va afficher "true", puisque l'expression régulière modele est présente plusieurs fois dans la chaine texte.
L'affichage aurait été le même si le script était réduit à ceci:
var modele = new RegExp("e");
var reponse = modele.test("Seuls les bons professeurs forment les bons autodidactes, disait Jean-François Revel");
alert(reponse);
Et, pour rester conforme à la théorie présentée dans la séquence précédente, la variable modele, écrite sous forme d'expression régulière aurait pu se noter de deux façons différentes, mais équivalentes:
1 var modele = new RegExp("e");
ou
2 var modele = /e/g;
Dans la séquence précédente, nous avions parlé de 'joker limité'. Il s'agissait de mettre entre crochets des alternatives possibles pour un même caractère. Écrire "t[aoui]c", c'était accepter comme variantes l'une des chaines 'tac', 'toc', 'tuc', 'tic', mais pas 'ttc', ni ''tec" dans l'expression régulière. De même écrire "[f-k]es" serait accepter comme variantes l'une des chaines 'fes', 'ges', 'hes'... 'kes', mais pas 'les', ni ''tes".
Vous pouvez donc dire ce qu'affichera le script suivant :
var modele = new RegExp("[f-k]es","g");
var reponse = modele.test("Seuls les bons professeurs forment les bons autodidactes, disait Jean-François Revel");
alert(reponse);
Vous avez répondu "false"? Je ne peux pas marquer mon accord ni affirmer que vous n'avez rien compris. Une relecture ou une visite chez un bon opticien pourrait peut-être vous aider... voyons cela de plus près:
Seuls les bons professeurs forment les bons autodidactes, disait Jean-François Revel
Il fallait donc répondre "true" puisque une des alternatives était présentes dans la chaine testée.
Encore une, en JS... une expression régulière qui recherche non plus un joker dans une chaine de caractères, mais un "joker limité" dans une chaine. Ainsi, pour rechercher si une chaine de caractères contient bien l'une des chaines 'tac', 'toc', 'tuc', 'tic', mais pas 'ttc', ni ''tec" dans l'expression régulière, on notera simplement "t[aoui]c" entre guillemets ; et, à l'intérieur de la chaine recherchée, on notera entre crochets "[]" les différentes valeurs uniques acceptées en cette place.
À l'intérieur d'une classe, on peut encore (toujours entre les crochets) placer un '-' ou 'trait d'union' qui indiquera qu'il s'agit de plage de valeurs acceptées (de celle qui précède à celle qui suit le trait d'union. Ainsi :
[r-x] est équivalent à [rstuvwx]
[5-9] est équivalent à [56789]
[r-x5-9] est aussi équivalent à [rstuvwx56789]
le modèle des nouvelles plaques françaises acceptables se noterait :
"[a-z][a-z]-[0-9][0-9][0-9]-[a-z][a-z]"
et l'avenir nous montrera que l'on peut simplifier cette écriture
À l'intérieur d'un classe on peut aussi (toujours entre les crochets) placer un 'caret' ou '^' au début de la classe, ce qui indiquerait la négation de la classe ou le rejet des caractères de la classe. Ainsi :
"[^a-z]" indiquerait que le mot ne peut pas contenir de lettres en bas de casse (vulgairement dénommées minuscules [voir ici]).
Attention, à l'extérieur d'un classe on peut aussi (toujours entre les crochets) placer un 'dollar' ou '$' derrière la classe, ce qui indiquerait que la chaine devrait se terminer par un des caractères de la classe. Ainsi :
"[a-z]$" indiquerait que le mot ne peut pas se terminer que par des lettres en bas de casse (vulgairement dénommées minuscules [voir ici]), mais ni par des signes de ponctuation, ni espaces, ni chiffres, ni capitales (vulgairement dénommées majuscules [voir ici]).
Attention aussi, car à l'extérieur d'un classe on peut aussi (toujours entre les crochets) placer un 'caret' ou '^' devant la classe, ce qui indiquerait que la chaine devrait commencer par l'un des caractères de la classe. Ne pas confondre avec celui placé à l'intérieur de la classe qui nie ce qui suit. Ainsi :
"^[a-z]" indiquerait que le mot doit commencer par une lettre en bas de casse (vulgairement dénommée minuscule [voir ici]).
Ainsi aussi, pour vérifier qu'une phrase ne se termine pas sans ponctuation finale, on pourrait vérifier :
"[^a-z]$" qui empêcherait la chaine de se terminer par une lettre en bas de casse, mais admettrait les capitales et les chiffres, sans ponctuation, en fin de phrase...
Le 'crochet ouvrant' ou '[', est obtenu avec 'AltGr' et la touche à droite du 'P' sur clavier belge ;
le 'crochet fermant' ou ']', est obtenu avec 'AltGr' et la touche '$', plus à droite du 'P' sur clavier belge.
Ainsi, en écrivant :
var ma_variable = "Halte ! Stop ! Quelle est cette populace qui fait tant de shopping ?"; var expr = new RegExp("[ei]t","gi"); var rep1 = ma_variable.replace(expr,"888"); alert(rep1); // affichera 'Halte ! Stop ! Quelle est c888te populace qui fa888 tant de shopping ?' // car recherche globale
// mais 'Halte', 'Stop', 'est' et ' tant' n'ont pas 't' précédé d'un 'e' ou d'un 'i'
Exemple
|
Et une nouvelle, en JS... une expression régulière qui recherche non seulement les caractères dans une chaine de caractères, mais en plus qui peut préciser le nombre de fois que peut apparaitre chaque caractère dans la chaine. Ainsi, pour rechercher si une chaine de caractères correspondait bien aux anciennes plaques françaises (3 ou 4 chiffres suivis de 2 ou 3 lettres, le tout suivi de deux chiffres).
"+" derrière un caractère ou une classe (<==> {1,}),
signifie que ce qui précède soit présent "au moins une fois" ;
"*" derrière un caractère ou une classe (<==> {0,}),
signifie que ce qui précède soit présent "zéro ou plusieurs fois" ;
"?" derrière un caractère ou une classe (<==> {0,1}),
signifie que ce qui précède soit présent "au plus une fois", c-à-d "zéro ou une fois" ;
"{}" derrière un caractère ou une classe,
signifie que ce qui précède soit présent dans des limites d'occurences précisées ;
"{3}" derrière un caractère ou une classe,
signifie que ce qui précède soit présent exactement 3 fois ;
"{3,}" derrière un caractère ou une classe,
signifie que ce qui précède soit présent 3 fois ou plus ;
"{,3}" n'est pas admis en JavaScript (alors que "{0,3}" l'est),
mais l'est en Java et signifie en Java 3 fois ou moins ;
"{2,4}" derrière un caractère ou une classe,
signifie que ce qui précède soit présent 2 à 4 fois.
Aïe ! Gros problème en JS... une expression régulière qui recherche des caractères dans une chaine de caractères, mais si elle doit trouver des caractères qui ont leur signification propre, comme les '+', '|', '?', '^', ' " ', '.' et autres.
Chez JS, pas de problèmes... tout est prévu.
Le "\" ou "backslask" ou "barre oblique inversée" est un caractère d'échappement qui permet de considérer le caractère qui suit comme un vrai caractère et pas dans l'usage différent que l'usage des expressions régulières lui a attribué. Ce "\" ne peut cependant pas être utilisé entre les crochets indiquant une classe.
Rechercher la présence d'un point dans une adresse mail...
en utilisant ".", JS cherche n'importe quel caractère...
en utilisant "\.", JS cherchera un point dans la chaine.
Voici donc une liste des caractères d'échappement les plus courants :
caractère non échappé
|
caractère échappé
|
\
|
\\
|
.
|
\.
|
$
|
\$
|
{
|
\{
|
}
|
\}
|
(
|
\(
|
)
|
\)
|
[
|
\[
|
]
|
\]
|
^
|
\^
|
?
|
\?
|
*
|
\*
|
+
|
\+
|
-
|
\-
|
Le lecteur attentif aura noté que l’ordre des éléments dans l’utilisation de la fonction match() diffère des fonctions test() et exec().
Dans la fonction exec() et dans la fonction test(), on écrira expressionReguliere.exec(chaineAtraiter)
tandis que dans la fonction match() on écrira chaineAtraiter.match(expressionReguliere).
L’ordre est inversé. Cela fait partie des incohérences du langage javascript …
voir suite >>>
voir suite >>>
[1] Depuis 1990 l'Académie française recommande d'ajouter un 's' au singulier des noms d'origines étrangères, sans vouloir adapter les règles propres à cette langue. Voir ici.
[2] Le lecteur sensible à la précision du vocabulaire ne confondra pas les majuscules et minuscules du grammairien et les capitales et bas de casse du typographe. Voir ici.