1
- Structure des expressions régulières
|
En JavaScript, les expressions régulières,
dont nous allons voir la grande utilité au travers des exemples qui
émaillerons ce paragraphe, constituent une classe d'objets, la classe
RegExp. Nous verrons qu'elles agissent sur
des chaînes de caractères pour permettre de les analyser,
les filtrer et de chercher des motifs
contenus dans celles-ci avec un niveau de précision adapté à
la problématique (du plus grossier au plus fin). Notons que ce concept
d'expressions régulières, très fortement inspiré
(c'est un euphémisme) de celui du langage Perl, n'est apparu dans JavaScript
que depuis sa version 1.2.
|
|
Comment définit-on des expressions régulières
?
Un objet "expression régulière"
peut être introduit et éventuellement défini grâce
au constructeur de la classe, RegExp(), en
écrivant simplement une instruction du type var
R = new RegExp(). Dans cet exemple, l'expression régulière
R existe, mais aucune valeur ne lui a été affectée. Comme
pour les constructeurs que nous avons déjà rencontrés,
on aurait pu définir sa valeur en la précisant, sous forme d'une
chaîne de caractère, en paramètre du constructeur. Un
tel objet peut aussi être introduit de façon littérale
en utilisant des marqueurs spécifiques délimitant l'expression
: '/'. Nous pourrions ainsi avoir : var
R = /a/. (Cette expression, dans le cadre de l'analyse d'une chaîne
impose simplement que celle-ci contienne le caractère a).
Une écriture équivalente utilisant le constructeur eut été
: var R : RegExp("a").
Dans une expression régulière, outre les caractères
devant se retrouver physiquement dans la ou les chaînes qui seront traitées
par celle-ci, on rencontre un nombre non négligeable de caractères
"outils' dont il est important de bien saisir la sémantique pour
pouvoir les utiliser de façon pertinente et réaliser ainsi des
modèles efficaces et concis. Ces caractères sont de trois types
: les caractères définissant des littéraux,
les caractères d'ensemble, les caractères
de groupement et enfin les caractères
de répétition.
|
|
Les littéraux
Ces caractères contiennent, outre tous les caractères
alphanumériques, une représentation des caractères non
imprimables (tabulation, retour chariot, saut de ligne, saute de page, etc.)
ainsi que des caractères qui étant utilisés en tant que
caractères "outils" doivent néanmoins avoir une représentation
différente pour pouvoir être analysés dans une chaîne.
Ces caractères littéraux seront en introduit par le caractère
"backslash" : \.
En voici la liste :
Caractère
|
Signification
|
Alphanumérique
|
Lui-même
|
\
/
\ \
\ .
\ +
\ *
\ ?
\ |
\ }
\ {
\ (
\ )
\ [
\ ]
|
/
\
.
+
*
?
|
}
{
(
)
[
]
|
\t
\r
\n
\f
\v
|
tabulation
horiz.
retour chariot
saut de ligne
saut de page
tabulation vert.
|
\xxx
\xhh
|
car.
ASCII de code octal xxx
car. ASCII de code hexa hh
|
A titre d'exercice, vous allez donner un texte en entrée
en tâchant d'y inclure la lettre dont le code ASCII octal 112 est attendu...
essai
Si vous voulez un peu tricher, consultez une table des codes ASCII... Mais
elle est souvent en décimal et hexadécimal ! Ce sera une occasion
pour jongler entre les bases de numération !!! (On n'a rien sans rien
;-))
|
|
Les caractères d'ensemble
Les caractères d'ensemble permettent de construire
à la demande une collection de caractères
ou de désigner des collections prédéfinies.
Ils pourront indiquer que l'un quelconque des caractères qu'ils représentent
doit apparaître ou, au contraire, qu'aucun des caractères qu'ils
représentent ne doit apparaître.
Il faut ajouter que dans le cas où les codes des caractères
de la collection à désigner constituent une suite, on pourra
représenter cette suite par seulement le premier
et le dernier caractères séparés par un tiret.
Citons, par exemple les caractères de l'alphabet majuscules ([A-Z]),
minuscules ([a-z]), les chiffres décimaux
([0-9]), hexadécimaux ([0-9A-F]),
etc.
Si, au contraire on désire représenter un
caractère pouvant être quelconque hormis appartenir à
un ensemble parfaitement cerné, on utilisera le caractère de
complémentarité ^ en début
d'ensemble ; par exemple [^!?.,;] désigne
tout caractère qui n'est pas un signe de ponctuation. Voici la liste
de ces caractères :
Caractère
|
Signification
|
[....]
[^....]
.
\s
\S
\w
\W
\d
\D
|
Un
qcq des caractères contenus
Aucun des caractères contenus
Caractère qcq sauf saut de ligne
équivaut à [^ \n]
Tout caractère de césure
équivaut à [ \t\r\n\f\v]
Aucun caractère de césure
équivaut à [^ \t\r\n\f\v]
Tout caractère alphanumérique
équivaut à [a-zA-z0-9]
Aucun caractère alphanumérique
équivaut à [^a-zA-z0-9]
Tout chiffre (décimal)
équivaut à [0-9]
Aucun chiffre (décimal)
équivaut à [^0-9]
|
Si, par exemple, on désire analyser le mot JavaScript
contenant ou pas les majuscules et encadré de deux caractère
de césure, nous définirons ainsi le modèle : /\s[Jj]ava[Ss]cript\s/.
Attention : avec cette expression on accepte l'écriture Javascript
qui n'est pas gênante, mais aussi javaScript qui peut ne pas
être souhaitée.
ATTENTION : A l'intérieur d'un ensemble (ou d'un complémentaire d'ensemble), pour représenter des "caractères outils" du premier sous-groupe ("/", "+", "*", "?", "(", ")", etc), point n'est besoin de les faire précéder du caractère "\". Les seuls qui doivent l'être (car ils introduisent une ambiguïté) sont : "\" et "]"
|
|
Les caractères de groupement (et de référencement)
Le caractère de groupement a pour fonction de regrouper
plusieurs éléments constituant un sous-motif du modèle
en un seul élément. Le groupement s'opère simplement
en l'encadrant d'une paire de parenthèses. Il y a plusieurs utilités
à pouvoir regrouper des éléments :
- on peut ainsi faire porter les caractères
de répétition que nous verrons plus loin sur l'ensemble
des éléments du modèle ainsi regroupés. Ainsi,
c'est cet ensemble qui sera dupliqué et non les éléments
constitutifs individuellement ;
- on peut aussi référencer ce groupement
de façon à prévoir une autre occurrence des éléments
de la chaîne analysés avec lesquels il a été apparié,
plus loin dans le modèle.
Le référencement dont il vient d'être question s'opère
par l'apparition dans l'expression régulière du caractère
\n où n désigne le n° de parenthésage auquel
il fait référence. Pour illustrer d'un exemple simple, supposons
que l'on veuille analyser la chaîne JavaScript encadrée de simples
ou doubles guillemets (les deux devant être identiques bien entendu).
Si l'on analyse à l'aide de l'expression régulière
/['"]JavaScript['"]/, les écritures
'JavaScript" et "JavaScript' seront
reconnues correctes, ce que nous refusons. En fait, l'expression d'analyse
devra être de la forme : /(['"])JavaScript\1/.
Essayez
!
Grâce à cet essai, on constate que cette expression autorise
en début de chaîne le caractère '
ou le caractère ", mais une fois
le premier analysé, il contraint le second à lui être
identique.
|
|
Les caractères de répétition
Ce sont des caractères dont la fonction est de prévoir
dans le modèle un nombre d'occurrences successives du littéral,
du groupement ou d'élément d'ensemble sur lequel ils portent.
Caractère
|
Signification
|
*
+
?
{n}
{n,m}
{n,}
|
Un
nombre indéfini de fois [0,x], x >= 0
Au moins une fois [1,x], x > 0
Eventuellement une fois [0,1]
Exactement n fois
Au moins n et au plus m fois [n,m]
Au moins n fois [n,x], x >= n
|
Chacun sait que tout individu français est immatriculée
par un numéro INSEE plus connu pour certains d'entre eux (pas pour
tous, hélas) sous le nom de numéro "sécu".
Ce numéro comporte un formatage bien précis : un chiffre pour
le sexe (1 ou 2), deux pour l'année de naissance, deux pour le mois,
deux pour le département de naissance, trois pour la ville, trois pour
l'ordre, tous ces champs étant séparés par un espace,
puis un slash (/) et enfin deux chiffres pour la clé. Vous allez proposer
une expression régulière, la plus courte possible, permettant
d'opérer l'analyse de ce type d'information, puis vous la testerez
contre votre numéro INSEE afin de vérifier soit l'un, soit l'autre...
ATTENTION
: Veillez à bien refermer parenthèses, crochets, accolades,
etc. si vous en utilisez, sinon, sous Netscape, la compilation de votre expression
provoquera une erreur. Si d'aventure cela se produit, remontez simplement
à la fenêtre précédente de l'historique du navigateur.
|
|
Le caractère de choix
Le caractère de choix permet
de prévoir, dans l'expression régulière, le
choix entre différents sous-motifs, séparés par
le caractère |. Comme pour les caractères
de répétitions, celui-ci peut porter sur un ou plusieurs littéraux,
ensembles ou groupements.
Par exemple, pour analyser une adresse, on peut imaginer
l'expression suivante :
Dans cette expression apparaissent plusieurs groupements.
Parmi eux, certains constituent des choix (statut du destinataire, de la voie),
d'autres permettent de faire porter un caractère de répétition
sur plusieurs sous-motifs successifs. Par exemple, 'identité du destinataire
est composée d'au moins un mot, son nom (d'où le caractère
de répétition + qui impose au moins 1) ; ce nom peut être
composé ; il peut être précédé ou suivi
d'un prénom, lui-même pouvant être composé chacun
de ces éléments répondant au même modèle.
Avec une telle expression, on peut analyser une adresse du type :
M. Jean-Claude Vandamme
17, Rue de la Castagne
31500 TOULOUSE |
|
|
Les caractères de positionnement
Nous avons seulement vu, jusqu'ici, des appariements de
caractères. Il existe aussi la possibilité d'apparier
et donc, de contraindre encore, selon la position dans
la chaîne. Cela est d'un grand intérêt car on va
pouvoir mettre en place des ancrages de motifs. Prenons l'exemple d'un identificateur
qui doit commencer forcément par une lettre éventuellement suivie
de lettres ou de chiffres.
Vous seriez tenté de proposer, avec beaucoup d'assurance, l'expression
régulière suivante : /[A-Za-z]\w*/.
Considérons donc la chaîne 03Trois1.
Je suis au regret de vous dire que l'appariement va réussir et donc
que 03Trois1 sera bien pris comme un identificateur
!!!
En fait pour toutes les expressions régulières
que l'on a vues jusqu'ici, la vérification se contentait de tester
si dans la chaîne fournie, une partie de celle-ci répondait au
modèle décrit par l'expression régulière. Si vous
avez réussi à faire l'exercice sur le n° INSEE, proposez
à présent quelque chose du style "Tartempion
1 85 06 13 055 312/51.. Ouf!!!". Vous allez constater que
tout baigne !!! Précisément, la partie centrale qui apparaît
ici en italique aura répondu au modèle. De la même manière,
dans 03Trois1, c'est en fait Trois1
qui aura constitué un parfait identificateur !!
Il faudrait donc contraindre l'analyse à appliquer
le modèle dès le début de la chaîne afin que [A-Za-z]
ne pouvant s'apparier à 0 , 03Trois1
ne soit pas retenu comme identificateur. Voici ces caractères de positionnement
:
Caractère
|
Signification
|
^
$
\b
\B
|
Ancre en début
de chaîne
Ancre en fin de chaîne
Ancre sur limite de mot (entre \w et \W)
Ancre sur non limite de mot
|
Ainsi, en utilisant l'expression /^[A-Za-z]\w*/,
l'analyse d'un identificateur sera pertinente. Pour le numéro INSEE,
et seulement lui, on utilisera le caractère ^
en début d'expression tandis que le caractère $
la terminera.
Ces caractères de positionnement, dont on comprend
bien l'énorme importance, sont hélas, trop peu nombreux. Ce
défaut disparaîtra avec JavaScript 1.3 qui permettra de définir
le type de positionnement que l'on veut. Par exemple (?=[0-9])
permet de définir un ancrage avant un chiffre, tandis que (?![0-9])
désigne un ancrage avant tout caractère qui ne soit pas un chiffre
(Å(?=[^0-9])).
|
Ne pas
confondre le caractère d'ancrage en début avec le caractère
de complémentarité. Même s'ils ont une
représentation similaire, il n'y a aucune ambiguïté car
l'un se situe obligatoirement en début d'expression (après
/) tandis que l'autre ne peut apparaître
qu'en début de définition d'ensemble (après [). |
|
|
Les attributs d'appariement
Les attributs d'appariement sont au nombre de deux. Ils
se placent après l'expression régulière sur laquelle
ils portent.
On dispose de l'attribut i
qui indique s'il est présent que l'analyse de la chaîne doit
se faire sans tenir compte de la casse des caractères. Cela permet,
entre autres, de simplifier les expressions et si nous reprenons les exemples
précédents, l'expression décrivant un identificateur
pourra s'écrire /^[AZ]\w*/, celle
des nombres hexadécimaux, /^[AF09]+$/i.
Nous allons présenter dans les prochains paragraphes
des méthodes permettant, sur la base d'une expression régulière,
de rechercher des sous-chaînes de la chaîne de caractères
source. En présence de l'attribut g, ce sont effectivement toutes les
portions s'appariant avec l'expression qui seront recherchées. Dans
le cas contraire, , la recherche s'arrêtera dès la première
rencontrée.
|
2
- Les propriétés & méthodes de la classe RegExp
|
La propriété lastIndex
(non implanté sous I.E.)
C'est une propriété accessible en lecture/écriture
dans laquelle est enregistré, dans le cas de recherches globales, l'indice
dans la chaîne source, à partir duquel la recherche devra reprendre.
Cette propriété est en particulier utilisée par les méthodes
test() et exec()
que nous allons voir.
|
|
La propriété source
Accessible en lecture seulement, cette propriété
est une chaîne de caractères contenant
le texte de l'expression régulière référencée.
Par exemple, si vous avez fourni une expression régulière, dans
l'exercice sur le numéro INSEE, vous pouvez la revoir en cliquant ici.
|
|
Les propriétés global
et ignoreCase
(non implanté sous I.E.)
Ces deux propriétés sont elles aussi accessibles
seulement en lecture sont deux booléens permettant de récupérer
la valeur des attributs de
l'expression régulière référencée.
Si global est vrai, cela signifie que la recherche
d'appariements est globale à toute la chaîne ; si ignoreCase
est vrai il n'est pas tenu compte de la casse des caractères.
|
|
Nous allons voir à présent les
propriété statiques de la classe RegExp.
Rappelons qu' à la différence des propriétés d'instance
qui s'applique à tout objet instance de la classe, chaque propriété
statique, est unique dans la classe et donc commune à tous les objets
de cette classe. |
|
Les propriétés RegExp.lefContext
& RegExp.rightContext (non implanté sous
I.E.)
A chaque fois qu'une recherche d'appariement entre une expression
régulière et une chaîne de caractères est opérée,
par des méthodes que nous verrons plus loin, qu'elles soient de la
classe RegExp ou de la classe String, ces indicateurs seront positionnés.
Le premier contiendra la partie de la chaîne
située à gauche du dernier appariement effectué,
tandis que le second contiendra la partie droite.
A noter que ces propriétés sont équivalentes
respectivement à RegExp["$`"]
et RegExp["$'"].
|
|
Les propriétés RegExp.lastMatch
& RegExp.lastParen (non implanté sous I.E.)
Les deux précédentes propriétés
permettent de récupérer les contextes gauche et droit du dernier
appariement opéré. Ce qui se trouve entre les deux, c'est à
dire la partie de la chaîne source mise en concordance
avec l'expression régulière sera disponible dans la propriété
lastMatch.
A l'intérieur de la sous-chaîne appariée
contenue dans lastMatch, on peut de plus dégager
la partie qui s'est appariée au dernier groupement
du précédent appariement. Celle-ci est contenue dans
lastParen. Il est intéressant de noter
que l'on peut obtenir les sous-chaînes mises en appariement avec les
neuf premiers groupements par l'intermédiaire des propriétés
RegExp.$1, RegExp.$2, ..., RegExp.$9.
A noter aussi que ces propriétés sont équivalentes
respectivement à RegExp["$&"]
et RegExp["$+"].
|
|
Un bon exemple valant plus que de longs discours, étudiez le comportement
de ces différentes propriétés sur la base d'une expression
régulière de la forme /([A-Z]([a-z]+)\d([,.]))/g
et d'une chaîne de caractères ayant pour valeur : "Un1,Deux2,Trois3,Quatre4,Cinq5.".
|
|
La propriété RegExp.multiline
(non implanté sous I.E.)
Ce booléen permet de préciser si la chaîne
sur laquelle agit l'expression régulière contient une seule
ou plusieurs ligne. Selon le cas, le comportement pourra être différent
et c'est en particulier le cas pour les ancrages de début et de fin.
Dans le cas où le texte n'est pas précisé multiligne,
^ représente le début de la
chaîne et $, la fin de la chaîne,
même s'il contient des littéraux \n.
Dans le cas où ce même texte est déclaré multiligne,
^ représente le début e
et $, la fin de chaque ligne.
Modifions légèrement les chaînes et expressions régulières
du précédent exemple.
La chaîne utilisée va contenir plusieurs lignes
: "Un1,\nDeux2,Trois3,\nQuatre4,Cinq5.".
Par ailleurs, l'expression régulière va pouvoir
revêtir deux formes :
Forme 1 = /^([A-Z]([a-z]+)\d([,.]))+$/g
et Forme 2 = /^([A-Z]([a-z]+)\d([,.]\n?))+$/g
Enfin, nous allons considérer le cas où multiline
est vrai et celui où multiline est faux...
Voyons ce que cela donne...
|
Forme 1
|
Forme 2
|
multiline VRAI
|
|
|
multiline FAUX
|
|
|
A noter que cette propriété est équivalente
à RegExp["$*"].
|
|
La méthode compile(<chaîne>[,
<attributs>])
Lorsque dans un script interviennent plusieurs expressions
régulières, soit qu'elles soient fournies en paramètre
soit même par l'utilisateur comme ce fut le cas dans l'exercice sur
le numéro INSEE, plutôt que de créer pour chacune un objet
RegExp, il est sûrement avantageux d'utiliser,
si cela s'y prête, un seul objet. Dans ces conditions, les expressions
régulières successives qui lui seront affectées seront
tout d'abord fournies sous forme de chaîne qu'il faudra donc transformer
ensuite 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().
On peut déplorer que cette méthode ne récupère
pas les erreurs de syntaxe qui peuvent apparaître dans le modèle
fourni sous forme de chaîne. En particulier, une erreur de parenthésage
dans les groupements rend Netscape fou de rage !...
|
|
Les deux méthodes de la classe RegExp
qu'il nous reste à voir ont une utilité voisine et complémentaire.
Les deux opèrent un appariement entre l'expression régulière
référencée et la chaîne de caractères passée
en paramètre, mais l'une renvoie seulement un booléen signifiant
qu'au moins un appariement a pu avoir lieu, alors que l'autre renvoie, sous
forme d'un tableau, des informations plus complètes sur les sous-expressions
appariées.
Ces deux méthodes affectent et utilisent deux propriétés
qui n'ont pas été citées plus haut : index
et input. index
contient la position du caractère de la chaîne à partir
duquel l'appariement a eu lieu et input fait
référence à la chaîne elle-même. Si l'une
ou l'autre de ces méthode est rappelée sans paramètre,
par défaut, c'est la chaîne référencée par
input qui sera utilisée.
|
|
La méthode test(<chaîne>)
(buggé sous I.E.)
Cette méthode essaie d'opérer un appariement
entre l'expression régulière référencée
et la chaîne de caractères donnée en paramètre
à partir de l'indice spécifié par la propriété
lastIndex. Si un appariement est possible,
lastIndex est réactualisé et
la valeur booléenne renvoyée est true.
Dans le cas contraire, la valeur renvoyée est false
et lastIndex est remis à 0.
|
|
La méthode exec(<chaîne>)
(buggé sous I.E.)
L'autre méthode d'appariement, s'évalue sur
le même type de donnée que la précédente (expression
régulière référencée et chaîne de
caractères en paramètre). Comme elle, elle essaie donc de procéder
à l'appariement de ces deux données. En cas d'échec,
la valeur de retour est null. Dans le cas contraire,
la valeur retournée est un tableau contenant en 0, la sous-chaîne
appariée avec l'expression régulière et dans le éléments
suivants les sous-chaînes appariées avec les éventuels
groupements parenthésés. Par ailleurs, en cas d'appariement,
cette méthode actualise lastIndex, si
bien que si elle est rappelée avec la même référence,
elle procède à une nouvelle recherche à partir de cet
emplacement. Comme pour la méthode précédente, en cas
d'échec, lastIndex est remis à
0.
|
3
- Les méthodes de la classe String mettant en jeu les expressions régulières
|
La méthode match(<expr.
régul.>)
Cette méthode qui est à rapprocher de la méthode
exec() que l'on vient de voir, hormis le fait
que celle-ci fait référence à un chaîne et a pour
paramètre une expression régulière. Elle permet de
rechercher dans la chaîne référencée la ou les
portions de celle-ci qui répondent à un modèle
(expression régulière) fourni en paramètre. Dans le cas
où aucune portion de la chaîne ne répond au modèle,
la valeur retournée est null. Dans le
cas contraire, la valeur rendue est un tableau construit de façon différente
selon que l'on ne recherche qu'une (la première à gauche) mise
en concordance ou chacune d'elles. Dans le premier cas, le premier élément
du tableau comporte la sous chaîne répondant au modèle
et les éléments suivants contiennent les sous-parties correspondant
aux éventuelles sous expressions parenthésées du modèle.
Dans le cas où toutes les concordances sont recherchées, le
tableau rendu se limite à chacune des parties de la chaîne source
répondant au modèle.
On voit donc que la similitude que l'on trouvait au début
entre exec() et match()
n'est pas totale puisque alors que exec() n'évalue
qu'un seul appariement, match() effectue tout
les appariements que l'expression autorise sur la chaîne passée
en paramètre. En particulier, l'attribut g
prendra pleinement sa signification dans match()
ce qui n'est pas le cas dans exec().
Dans l'exemple qui suit, nous allons comparer les comportements
de match() et exec()
dans un contexte de recherche globale ou pas.
Le
programme... |
|
var Tab;
var Texte="Un1,\nDeux2,Trois3,\nQuatre4,Cinq5."; |
|
var Model=/([A-Z]([a-z]+)\d([,.]))+/g; |
var Model=/([A-Z]([a-z]+)\d([,.]))+/; |
Tab
= Model.exec(Texte); |
Tab = Texte.match(Model); |
|
|
if (Tab==null) alert("Aucun
appariement n'est possible !");
else {
S="";
for(var i=0;i<Tab.length;i++)
S+= "En "+i+" : "+Tab[i]+"\n";
alert(S);
} |
|
|
Voici le canevas du programme qui va être utilisé,
dans lequel, est mise en évidence (enfin, j'espère !...) la
combinatoire des tests qui vont être fait...
NB : Cette méthode met à jour les propriétés
statiques de RegExp.
|
|
La méthode replace(<expr.
régul.>,<remplacement>)
Cette méthode référence une chaîne
de caractères dans laquelle une sous-chaîne appariée avec
l'expression régulière donnée dans le premier paramètre
va être remplacée par le second paramètre. Généralement,,
le remplacement s'opère par une chaîne de caractères.
Mais il peut advenir que ce soit la sous-chaîne extraite de l'appariement
que l'on veuille modifier tout en gardant tout ou partie des éléments
qui la composent. Dans ces conditions il est souhaitable de pouvoir accéder
à ces parties sous forme paramétrée afin de les répercuter
dans le paramètre de remplacement sous la forme et dans l'ordre désirés.
Cela est possible si l'on prévoit dans l'expression régulière
des groupement parenthésés que l'on peut ensuite référencer
dans le paramètre remplacement par les caractères $1,
$2,...,$9. Plusieurs
caractères faisant référence à diverses portions
de la chaîne sont ainsi disponibles :
Caractère
|
Signification
|
$1,
$2,..., $9
$&
$'
$`
$+
|
sous-chaînes appariées aux 9
premiers groupements
sous-chaîne appariée à l'expression régulière
sous-chaîne à droite de l'appariement (idem
rightContext)
sous-chaîne à gauche de l'appariement (idem leftContext)
dernier groupement apparié
|
Exemple :
Les dates sont codées différemment dans les pays anglo-saxons
et en France. Sur la base de deux chiffres pour le jour (jj), le mois(mm)
et l'année (aa), une date sera codée en France jjmmaa, alors
qu'en Angleterre, par exemple, elle sera codée mmjjaa. Quant au séparateur,
qu'il soit " ", "/" ou "-", il demeurera identique.
En supposant que le texte sur lequel porte l'opération soit référencé
par la variable Txt, le problème sera
résolu par :
Txt.replace(/\s*(\d{1,2})([ \/-])(\d{1,2})\2(\d{1,2})\s*/,"$3$2$1$2$4")
ATTENTION :
Ces caractères n'ont de validité qu'à l'intérieur
de l'appel à la méthode replace().
Si vous essayez de les utiliser à l'extérieur vous aurez de
grosses surprises !... A moins que vous preniez en compte qu'ils sont aussi
des propriétés statiques de la classe RegExp
et que vous les utilisiez sous la forme qui convient.
Par ailleurs, de façon logique, lorsque aucun appariement n'est possible,
la chaîne référencée reste inchangée.
|
|
La méthode search(<expr.
régul.>)
Nous avons vu, dans le chapitre précédent,
la méthode indexOf()
qui permettait de déterminer l'emplacement d'une sous-chaîne
dans une chaîne donnée en référence. En particulier,
nous avons mis en évidence ses faiblesses en l'utilisant dans un exemple
où l'on cherchait à compter le nombre d'occurrences d'un caractère
car pour prendre en compte la casse de celui-ci, il nous aurait fallu procéder
à deux appels, l'un pour rechercher les occurrences minuscules et l'autre
pour les majuscules. La méthode présentée ici bénéficie
des possibilités offertes par les expressions régulières
pour rechercher une sous-chaîne vérifiant
un modèle particulier. Reprenons l'exemple auquel il était
fait référence à l'instant :
Le
texte... |
"Il est certain que JavaScript est un langage simple
à apprendre. Il n'en est pas pour autant rudimentaire... "
|
Le
programme (version search)... |
var Compt = 0;
var Deb = Texte.search(/i/i);
while (Deb != -1) {
Compt++;
Deb = RegExp.rightContext.search(/i/i);
}
alert("Nbre d'occurrences de 'i' : " + Compt); |
Les
résultats... |
indexOf()
|
search()
|
On constate qu'avec indexOf("i"),
la valeur retournée correspond au nombre de caractères très
précisément identiques à celui donné en paramètre.
Tandis qu'avec search() on peut préciser,
grâce à l'attribut i que la casse
est indifférente. On voit aussi que malgré le fait que search()
ne dispose pas de paramètre indiquant l'indice de début de recherche,
comme c'était le cas pour indexOf(), grâce
à la propriété statique rightContext,
on peut balayer la totalité de la chaîne fournie. Ces propriétés
de classe n'existant pas sous Internet Explorer, cet exemple ne fonctionnera pas
de façon satisfaisante sous ce navigateur.
NB : Cette méthode met à jour les propriétés
statiques de RegExp.
|
|
Pour terminer signalons une autre méthode de la classe
String pouvant utiliser une expression régulière.
Nous avons vu dans le chapitre précédent la méthode split(),
qui, sur la base d'un séparateur fourni en paramètre, transformait
la chaîne référencée en un tableau dont les éléments
étaient la succession des sous-chaînes ainsi séparées.
Cette méthode, en l'état, atteint vite ses
limites. Si, par exemple, nous voulons obtenir un tableau constitué
des différents mots d'un texte sur la base d'un seul séparateur,
on va se heurter à plusieurs problèmes. Tous les caractères
de ponctuations vont soit faire partie de mots (c'est le cas de la virgule
ou du point, toujours accolés au mot qui les précède),
soit constituer des mots eux-mêmes (c'est le cas de ; ? ! qui réclament
un espace de part et d'autre). Cela sans compter les espaces doublés
ou oubliés après la virgule ou le point, les apostrophes, etc.
Bref, les mots dégagés et donc le nombre de mots trouvés
seraient entachés d'erreur.
En utilisant l'expression régulière /[
',.;?!-]+/ en tant que séparateur, voire, beaucoup plus simplement
/\W+/, le problème sera résolu
!....
Considérons,par exemple, le texte suivant :
Ho
cà ! n'ai-je pas lieu de me plaindre de vous ?
Et, pour n'en point mentir, n'êtes vous pas méchante
De vous plaire à me dire une chose affligeante ?
(Tartuffe de Molère) |
|
|
Pour les deux expressions régulières, le
résultat est le même. Par contre, selon que vous serez
sous Netscape ou Explorer, le résultat sera 33 pour l'un, ce
qui est faux, ou 32 pour l'autre, ce qui est exact. Effectivement, regardez
bien l'énumération des mots répertoriés.
Celle-ci se termine par une virgule sous Netscape, preuve qu'il y a
un mot vide comptabilisé, ce qui n'est pas le cas avec Explorer.
NB : Vous remarquerez aussi, sous Explorer, que dans la deuxième
méthode, les caractères accentués ne sont pas reconnus
comme appartenant à \w. Ils sont donc inclus dans \W et donc
interprétés comme séparateurs. Si bien qu'un mot
contenant n caractères accentués sera décompté
pour n+1 mots. En particulier dans cet exemple, vous pouvez constater
que "méchante" compte pour deux mots à cause
du "é", alors que "à" (de "...plaire
à me dire..."), disparaît. Par ailleurs dans le texte
analysé, "çà" a en fait été
orthographié "cà", ce qui explique que le "c"
subsiste et qu'un mot soit ainsi détecté. Si l'orthographe
avait été correcte, il manquerait un mot au décompte
final... Conclusion ?
|
Testez vos acquis
concernant les expressions régulières !!!!
|