OVH Cloud OVH Cloud

Expressions régulieres

6 réponses
Avatar
Alexandre Lahure
Bonjour à tous,

Soit l'expression régulière :

var balise = /\[c=#[0-9a-f]{6}\]/i;

celle-ci représente une pseudo-balise avec un code couleur en hexa, de la
forme [c=#ff0000]
Je voudrais récupérer l'index de la dernière occurence de la balise dans
un texte.
Donc dans un premier temps, je fais :

var resultat = balise.exec("Du texte avec une balise [c=#ff0000], puis
une autre [c=#00ff00]");

D'après les docs javascript, la méthode exec est censée initialiser tout
un tas de propriétés de l'objet RegExp, notamment lastIndex et
lastMatch mais dans la réalité, aucune ne marche correctement, voire n'est
implémentée.

J'en arrive donc à mes questions :
- Existe t'il un moyen de faire la recherche à partir de la fin de la
chaine ?
- Si non, quelqu'un pourrait-il m'aider à composer une expression
régulière plus poussée pour arriver au même résultat ?

Merci d'avance

--
Alexandre

Computers are like air conditioners
They don't work when you open windows

6 réponses

Avatar
YD

Soit l'expression régulière :

var balise = /[c=#[0-9a-f]{6}]/i;

celle-ci représente une pseudo-balise avec un code couleur en hexa, de
la forme [c=#ff0000]
Je voudrais récupérer l'index de la dernière occurence de la balise
dans un texte.
Donc dans un premier temps, je fais :

var resultat = balise.exec("Du texte avec une balise [c=#ff0000],
puis une autre [c=#00ff00]");

D'après les docs javascript, la méthode exec est censée initialiser
tout un tas de propriétés de l'objet RegExp, notamment lastIndex et
lastMatch mais dans la réalité, aucune ne marche correctement, voire
n'est implémentée.


Sûr ?

Si tu veux capturer toutes les occurrences d'une exp. rég. avec exec, il
faut positionner l'indicateur global, donc écrire :
var balise = /[c=#[0-9a-f]{6}]/ig;

Exemple (largement inspiré de la doc) avec exec :

<pre><script type="text/javascript">
var balise = /[c=#[0-9a-f]{6}]/ig;
s="patati [c=#000001] patati [c=#000002] patati [c=#000003] patati [c=#000004]";
var r;
while ((r = balise.exec(s)))
document.writeln(r.index + "-" + r.lastIndex + "tt" + r);
</script></pre>


J'en arrive donc à mes questions :
- Existe t'il un moyen de faire la recherche à partir de la fin de la
chaine ?
- Si non, quelqu'un pourrait-il m'aider à composer une expression
régulière plus poussée pour arriver au même résultat ?


Si tu n'as besoin que de la dernière occurrence, il vaut mieux utiliser
s.match(balise) et interroger ensuite RegExp.lastIndex et RegExp.lastMatch.

--
Y.D.

Avatar
Alexandre Lahure
Soit l'expression régulière :
var balise = /[c=#[0-9a-f]{6}]/i;
celle-ci représente une pseudo-balise avec un code couleur en hexa, de
la forme [c=#ff0000]
Je voudrais récupérer l'index de la dernière occurence de la balise
dans un texte.
Donc dans un premier temps, je fais :
var resultat = balise.exec("Du texte avec une balise [c=#ff0000],
puis une autre [c=#00ff00]");

D'après les docs javascript, la méthode exec est censée initialiser
tout un tas de propriétés de l'objet RegExp, notamment lastIndex et
lastMatch mais dans la réalité, aucune ne marche correctement, voire
n'est implémentée.


Sûr ?

Si tu veux capturer toutes les occurrences d'une exp. rég. avec exec, il
faut positionner l'indicateur global, donc écrire :
var balise = /[c=#[0-9a-f]{6}]/ig;

Exemple (largement inspiré de la doc) avec exec :

<pre><script type="text/javascript"> var balise =
/[c=#[0-9a-f]{6}]/ig;
s="patati [c=#000001] patati [c=#000002] patati [c=#000003] patati
[c=#000004]";
var r;
while ((r = balise.exec(s)))
document.writeln(r.index + "-" + r.lastIndex + "tt" + r);
</script></pre>


J'utilise Mozilla 1.7 et Opera 7.54 et après avoir essayer ton exemple,
puis l'avoir appliqué à mon cas, le résultat est le même : r.lastIndex me
retourne undefined

J'en arrive donc à mes questions :
- Existe t'il un moyen de faire la recherche à partir de la fin de la
chaine ?
- Si non, quelqu'un pourrait-il m'aider à composer une expression
régulière plus poussée pour arriver au même résultat ?


Si tu n'as besoin que de la dernière occurrence, il vaut mieux utiliser
s.match(balise) et interroger ensuite RegExp.lastIndex et
RegExp.lastMatch.


La par contre, il y a un peu plus de réussite; RegExp.lastIndex me
retourne toujours undefined par contre RegExp.lasMatch me retourne bien la
derniere balise trouvée.
Cela venait sans doute du modificateur g.
Je vais me débrouiller avec le lastMatch et utiliser String.lastIndexOf()
pour obtenir l'effet voulu.
J'espere seulement que ca marchera partout.

Merci pour ton aide, j'etais un peu perdu, surtout depuis que
devedge.netscape.com n'existe plus et que le site perldoc (ou il y a la
doc sur le regexp) est inaccessible.

--
Alexandre

Computers are like air conditioners
They don't work when you open windows


Avatar
Alexandre Lahure
Soit l'expression régulière :
var balise = /[c=#[0-9a-f]{6}]/i;
celle-ci représente une pseudo-balise avec un code couleur en hexa,
de la forme [c=#ff0000]
Je voudrais récupérer l'index de la dernière occurence de la balise
dans un texte.
Donc dans un premier temps, je fais :
var resultat = balise.exec("Du texte avec une balise [c=#ff0000],
puis une autre [c=#00ff00]");

D'après les docs javascript, la méthode exec est censée initialiser
tout un tas de propriétés de l'objet RegExp, notamment lastIndex et
lastMatch mais dans la réalité, aucune ne marche correctement, voire
n'est implémentée.


Sûr ?

Si tu veux capturer toutes les occurrences d'une exp. rég. avec exec, il
faut positionner l'indicateur global, donc écrire :
var balise = /[c=#[0-9a-f]{6}]/ig;

Exemple (largement inspiré de la doc) avec exec :

<pre><script type="text/javascript"> var balise =
/[c=#[0-9a-f]{6}]/ig;
s="patati [c=#000001] patati [c=#000002] patati [c=#000003] patati
[c=#000004]";
var r;
while ((r = balise.exec(s)))
document.writeln(r.index + "-" + r.lastIndex + "tt" + r);
</script></pre>


J'utilise Mozilla 1.7 et Opera 7.54 et après avoir essayer ton exemple,
puis l'avoir appliqué à mon cas, le résultat est le même : r.lastIndex
me retourne undefined

J'en arrive donc à mes questions :
- Existe t'il un moyen de faire la recherche à partir de la fin de
la chaine ?
- Si non, quelqu'un pourrait-il m'aider à composer une expression
régulière plus poussée pour arriver au même résultat ?


Si tu n'as besoin que de la dernière occurrence, il vaut mieux utiliser
s.match(balise) et interroger ensuite RegExp.lastIndex et
RegExp.lastMatch.


La par contre, il y a un peu plus de réussite; RegExp.lastIndex me
retourne toujours undefined par contre RegExp.lasMatch me retourne bien
la derniere balise trouvée.
Cela venait sans doute du modificateur g.
Je vais me débrouiller avec le lastMatch et utiliser
String.lastIndexOf() pour obtenir l'effet voulu.
J'espere seulement que ca marchera partout.

Merci pour ton aide, j'etais un peu perdu, surtout depuis que
devedge.netscape.com n'existe plus et que le site perldoc (ou il y a la
doc sur le regexp) est inaccessible.


Bon, quand je dis un peu plus de réussite, c'est pas encore la panacée.
Sous Opera ainsi que sous Safari, ca refuse obstinément de marcher.
Donc on en revient à des problèmes d'impléméntation selon les navigateurs.

Ensuite je doute qu'il y ait un moyen de faire la recherche depuis la fin
de la chaine (ceci dit, si cela existe, je serais heureux de l'apprendre)
Reste finalement l'option d'étoffer un peu mon expression régulière, mais
alors là, j'ai besoin d'aide car j'ai bien fait quelques tentatives mais
rien de concluant.

Y aurait-il un grand maitre de la RegExp dans la salle ?

--
Alexandre

Computers are like air conditioners
They don't work when you open windows



Avatar
Pierre Goiffon
"Alexandre Lahure" a écrit dans le message de
news:
on en revient à des problèmes d'impléméntation selon les
navigateurs.


Personnellement dans mon job précédent, j'avais rencontré qq soucis avec les
regexp en JS pour notre back office. Ca s'était soldé par une mise à jour de
tout le monde des moteurs WSH... et j'avais pu constater qu'il y avait des
différences très importantes entre les versions !

Ensuite je doute qu'il y ait un moyen de faire la recherche depuis la
fin de la chaine


Vous pouvez utiliser ^ (début de chaine) et $ (fin de chaine)

Par exemple :

/toto$/

matchera les chaines se terminant par toto.

Avatar
YD
[...]

Bon, quand je dis un peu plus de réussite, c'est pas encore la panacée.
Sous Opera ainsi que sous Safari, ca refuse obstinément de marcher.
Donc on en revient à des problèmes d'impléméntation selon les navigateurs.


Mea maxima culpa ! Je me suis fié à la doc MS :-( qui ne respecte pas (qui
étend abusivement) le standard ECMAScript... auquel je me suis reporté pour
vérifier. L'objet RegExp disponible avec lastMatch, leftContext, etc. est aussi
une microsofterie.

Donc la propriété lastIndex n'est pas renvoyée par (je reprends le code du fil)
balise.exec(s), mais est positionnée dans l'instance d'objet RegExp et
accessible donc par balise.lastIndex. Ce qui nous donne le code modifié suivant
qui fonctionne à l'identique sur IE (JScript 5.6), Firefox 1.0 (basé sur
Mozilla 1.7.5) et Opera 7.54 :

<html><head><title></title></head>
<body>
<pre><script type="text/javascript">
var balise = /[c=#[0-9a-f]{6}]/gi;
s="patati [c=#000001] patati [c=#000002] patati [c=#000003] patati [c=#000004]";
s+=s;
s+=s;
s+=s;
s+=s;
s+=s;
s+=s;
s+=s;
var r;
while ((r = balise.exec(s)))
document.writeln(r.index + "-" + balise.lastIndex + "tt" + r);
</script></pre>
</body></html>

Pour récupérer l'index et la longueur de la dernière occurrence, il
suffit de remplacer les 2 dernières lignes du script par :
while ((r = balise.exec(s)))
{theStart = r.index; theEnd = balise.lastIndex; theMatch=r[0]};

et les variables theStart, theEnd et theMatch contiendront tout ce qui est
nécessaire (on peut ajouter theLength = theEnd - theStart; si besoin).


Ensuite je doute qu'il y ait un moyen de faire la recherche depuis la
fin de la chaine (ceci dit, si cela existe, je serais heureux de
l'apprendre)


Il ne me semble pas que ce soit prévu... Ceci dit, il est toujours
possible d'inverser la chaîne et le motif... Mais ce n'est pas sûr qu'on y
gagne en simplicité de traitement !

Ceci dit, je ne vois pas bien l'intérêt de chercher seulement la dernière
occurrence, puisque toutes ces balises seront finalement traitées, non ?

Reste finalement l'option d'étoffer un peu mon expression régulière,
mais alors là, j'ai besoin d'aide car j'ai bien fait quelques
tentatives mais rien de concluant.


J'utiliserai plutôt une expression simple comme celle que tu as donnée dans
le premier post en conjonction avec une boucle while, plutôt qu'une
expression forcément plus alambiquée du style

var balise = /([c=#[0-9a-f]{6}])(?!.*[c=#[0-9a-f]{6}])/gi;

(qui signifie une de ces balises non suivie d'une deuxième plus loin...)

qui te renverrait avec un seul exec la dernière occurrence dans ton texte mais
serait bien bien plus coûteuse en temps de traitement, surtout si la chaîne
en entrée est longue et qu'il y a beaucoup de balises.

--
Y.D.

Avatar
Alexandre Lahure
Mea maxima culpa ! Je me suis fié à la doc MS :-( qui ne respecte pas
(qui
étend abusivement) le standard ECMAScript... auquel je me suis reporté
pour
vérifier. L'objet RegExp disponible avec lastMatch, leftContext, etc.
est aussi
une microsofterie.

Donc la propriété lastIndex n'est pas renvoyée par (je reprends le code
du fil)
balise.exec(s), mais est positionnée dans l'instance d'objet RegExp et
accessible donc par balise.lastIndex. Ce qui nous donne le code modifié
suivant
qui fonctionne à l'identique sur IE (JScript 5.6), Firefox 1.0 (basé sur
Mozilla 1.7.5) et Opera 7.54 :

<html><head><title></title></head>
<body>
<pre><script type="text/javascript"> var balise =
/[c=#[0-9a-f]{6}]/gi;
s="patati [c=#000001] patati [c=#000002] patati [c=#000003] patati
[c=#000004]";
s+=s;
s+=s;
s+=s;
s+=s;
s+=s;
s+=s;
s+=s;
var r;
while ((r = balise.exec(s)))
document.writeln(r.index + "-" + balise.lastIndex + "tt" + r);
</script></pre> </body></html>


Super merci, ca marche aux petits oignons !

Pour récupérer l'index et la longueur de la dernière occurrence, il
suffit de remplacer les 2 dernières lignes du script par :
while ((r = balise.exec(s)))
{theStart = r.index; theEnd = balise.lastIndex; theMatch=r[0]};

et les variables theStart, theEnd et theMatch contiendront tout ce qui
est
nécessaire (on peut ajouter theLength = theEnd - theStart; si besoin).


Ensuite je doute qu'il y ait un moyen de faire la recherche depuis la
fin de la chaine (ceci dit, si cela existe, je serais heureux de
l'apprendre)


Il ne me semble pas que ce soit prévu... Ceci dit, il est toujours
possible d'inverser la chaîne et le motif... Mais ce n'est pas sûr qu'on
y
gagne en simplicité de traitement !

Ceci dit, je ne vois pas bien l'intérêt de chercher seulement la dernière
occurrence, puisque toutes ces balises seront finalement traitées, non ?


Ben en fait non ! la fonction que je prépare ouvre et ferme les balises,
donc dans le cas présent, la fonction regarde si la dernière balise entrée
est une balise ouvrante ou fermante et respectivement, ferme ou ouvre la
balise.

Reste finalement l'option d'étoffer un peu mon expression régulière,
mais alors là, j'ai besoin d'aide car j'ai bien fait quelques
tentatives mais rien de concluant.


J'utiliserai plutôt une expression simple comme celle que tu as donnée
dans
le premier post en conjonction avec une boucle while, plutôt qu'une
expression forcément plus alambiquée du style

var balise = /([c=#[0-9a-f]{6}])(?!.*[c=#[0-9a-f]{6}])/gi;

(qui signifie une de ces balises non suivie d'une deuxième plus loin...)

qui te renverrait avec un seul exec la dernière occurrence dans ton
texte mais
serait bien bien plus coûteuse en temps de traitement, surtout si la
chaîne
en entrée est longue et qu'il y a beaucoup de balises.


... A utiliser en dernier recours donc...

Merci encore

--
Alexandre

Computers are like air conditioners
They don't work when you open windows