Quelle est la différence entre la fonction exec () de RegExp et la fonction match () de String?

122

Si je lance ceci:

/([^\/]+)+/g.exec('/a/b/c/d');

J'ai compris:

["a", "a"]

Mais si je lance ceci:

'/a/b/c/d'.match(/([^\/]+)+/g);

Ensuite, j'obtiens le résultat attendu de ceci:

["a", "b", "c", "d"]

Quelle est la différence?

Justin Warkentin
la source
4
vous bouclez avec execpour obtenir toutes les sous-sélections.
zzzzBov
2
Notez que la seconde +n'est pas nécessaire car matchretournera déjà toutes les sous-expressions. .execn'en renvoie qu'un à chaque fois, donc il n'en a pas besoin non +plus.
pimvdb
3
En plus de cela, les quantificateurs imbriqués comme les deux avantages doivent être utilisés avec beaucoup de prudence car ils conduisent facilement à un retour en arrière catastrophique .
Marius Schulz
1
@MariusSchulz Merci pour le lien. Cela m'a amené à en apprendre davantage sur les quantificateurs possessifs et le groupement atomique. Très belles choses à comprendre.
Justin Warkentin

Réponses:

118

execavec une expression régulière globale est destiné à être utilisé dans une boucle, car il récupérera toujours toutes les sous-expressions correspondantes. Alors:

var re = /[^\/]+/g;
var match;

while (match = re.exec('/a/b/c/d')) {
    // match is now the next match, in array form.
}

// No more matches.

String.match fait cela pour vous et supprime les groupes capturés.

Ry-
la source
39
J'ai quelque chose à ajouter à cette réponse, il ne faut pas placer l'expression régulière littérale dans la condition while, comme ceci while(match = /[^\/]+/g.exec('/a/b/c/d')ou cela créera une boucle infinie !. Comme il est clairement indiqué dans le MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
yeyo
7
@yeyo: Plus précisément, il doit s'agir du même objet d'expression régulière. Un littéral n'accomplit pas cela.
Ry-
@ Ry- Je pense qu'il faut noter que ce comportement a été introduit dans ES5. Avant ES5 new RegExp("pattern")et /pattern/signifiait des choses différentes.
Robert le
75

Une image c'est mieux, tu sais ...

re_once = /([a-z])([A-Z])/
re_glob = /([a-z])([A-Z])/g

st = "aAbBcC"

console.log("match once="+ st.match(re_once)+ "  match glob="+ st.match(re_glob))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))

Regarde la différence?

Remarque: pour mettre en évidence, notez que les groupes capturés (par exemple: a, A) sont renvoyés après le modèle correspondant (par exemple: aA), ce n'est pas seulement le modèle correspondant.

Georg
la source
28

/regex/.exec()renvoie uniquement la première correspondance trouvée, tandis que les "string".match()renvoie toutes si vous utilisez l' gindicateur dans l'expression régulière.

Voir ici: exec , match .

Alex Ciminian
la source
23

Si votre expression régulière est globale et que vous effectuez une capture, vous devez utiliser exec. Match ne renverra pas toutes vos captures.

Match fonctionne très bien pour la correspondance (pas la capture). Vous l'exécutez une fois et il donne un tableau de toutes les correspondances. (bien que si l'expression régulière n'est pas globale, la correspondance affichera la correspondance suivie de captures)

Exec est ce que vous utilisez lorsque vous capturez, et chaque fois qu'il est exécuté, il donne la correspondance, suivie des captures. (la correspondance se comportera de manière à donner la correspondance complète suivie de captures, uniquement lorsque l'expression régulière n'est pas globale).

Une autre utilisation avec Exec consiste à obtenir l'index ou la position d'une correspondance. Lorsque vous avez une variable pour votre regex, vous pouvez utiliser .lastIndex et obtenir la position de la correspondance. Un objet regex a .lastIndex, et l'objet regex est ce que vous faites .exec. La correspondance de point est effectuée sur une chaîne et vous ne pourrez pas faire l'objet regex dot lastIndex

Une chaîne, a la fonction de correspondance, qui reçoit une expression régulière. Et une expression régulière, a la fonction exec, et reçoit une chaîne

exec vous exécutez plusieurs fois. match vous courez une fois

Il est bon d'utiliser match lorsque vous ne capturez pas et lors de la capture, vous pouvez utiliser exec qui est plus puissant car il est bon pour obtenir des captures, mais si vous avez utilisé match lors de la capture, voyez qu'il affiche les captures lorsque l'expression régulière n'est pas globale, mais ne le fait pas 't show capture lorsque le regex est global.

> "azb".match(/a(z)b/);
[ "azb", "z" ]

> "azb".match(/a(z)b/g);
[ "azb" ]
>

Une autre chose est que si vous utilisez exec, notez qu'il est appelé sur l'expression régulière, alors si vous avez utilisé une variable pour l'expression régulière, vous avez plus de puissance

Vous n'obtenez pas les correspondances lorsque vous n'utilisez pas la variable pour l'expression régulière, utilisez donc la variable pour l'expression régulière, lorsque vous utilisez exec

> /./g.exec("abc")
[ "a" ]
> /./g.exec("abc")
[ "a" ]
> /./g.exec("abc")
[ "a" ]
>
> /[a-c]/g.exec("abc")
[ "a" ]
> /[a-c]/g.exec("abc")
[ "a" ]
>

> var r=/[a-c]/g
> r.exec("abc")
[ "a" ]
> r.exec("abc")
[ "b" ]
> r.exec("abc")
[ "c" ]
> r.exec("abc")
null
>

Et avec exec, vous pouvez obtenir l '"index" du match

> var r=/T/g
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
2
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
6
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
9
> r.exec("qTqqqTqqTq");
null
> r.lastIndex
0
>

Donc, si vous voulez des index ou capturer, alors utilisez exec (gardez à l'esprit que comme vous pouvez le voir, avec le "index", le "index" qu'il donne est vraiment une nième occurrence, il compte à partir de 1. Donc vous pouvez dériver le bon index en soustrayant 1. Et comme vous pouvez le voir, il donne 0 - lastIndex de 0 - pour non trouvé).

Et si vous voulez étirer la correspondance, vous pouvez l'utiliser lorsque vous capturez, mais pas lorsque l'expression régulière est globale, et lorsque vous le faites pour cela, alors le contenu du tableau ne correspond pas à toutes les correspondances, mais est complet match suivi des captures.

barlop
la source
Oui, comprendre le fonctionnement de r.lastIndexest le facteur clé pour comprendre la différence entre execet match.
s'exécute le
@barlop "Le match ne correspondra pas à toutes les captures", sérieusement? "a, b, c, aa, bb, cc" .match (/ (\ w +) / g) => ["a", "b", "c", "aa", "bb", "cc" ]. Comment expliquer qu'il les a tous mis en cache?
MrHIDEn
@barlop If your regex is global, and you are capturing, then you must use exec. Match won't return all your captures.je l'ai sur la console. Copiez / collez simplement "a,b,c,aa,bb,cc".match(/(\w+)/g);Opera, Firefox.
MrHIDEn
@MrHIDEn Je n'utiliserais pas le langage que vous avez utilisé dans votre mauvaise citation. Et ce qui compte, c'est ce qui est montré et ce que nous pouvons voir ... s'il y a une mise en cache dans les coulisses n'est pas non plus pertinent. Et cela fait un moment que je n'ai pas examiné cela, mais il ne montre pas toutes les captures. Même si vous faites votre exemple "a,b,c,aa,bb,cc".match(/(\w+)/g) Ce qui se passe là-bas, c'est qu'il montre toutes les correspondances, et il se trouve que vous avez capturé chaque match, donc s'il montrait toutes les captures, il aurait exactement la même apparence (cntd)
barlop
(cntd) Alors peut-être que vous pensez qu'il montre les captures, mais ce n'est pas le cas, il montre les matchs
barlop
6

Le .match () fonction str.match(regexp)va effectuer les opérations suivantes:

  • s'il est un match , il retourne:
    • si le gdrapeau est utilisé dans l'expression rationnelle: il retournera toutes les sous-chaînes (en ignorant les groupes de capture)
    • si l' gindicateur n'est pas utilisé dans l'expression rationnelle: il retournera le même queregexp.exec(str)
  • s'il n'y a pas de correspondance, il retournera:
    • null

Exemples de .match () utilisant l' gindicateur:

var str = "qqqABApppabacccaba";
var e1, e2, e3, e4, e5;
e1 = str.match(/nop/g); //null
e2 = str.match(/no(p)/g); //null
e3 = str.match(/aba/g); //["aba", "aba"]
e4 = str.match(/aba/gi); //["ABA", "aba", "aba"]
e5 = str.match(/(ab)a/g); //["aba", "aba"] ignoring capture groups as it is using the g flag

Et .match () sans l' gindicateur équivaut à .exec () :

e1=JSON.stringify(str.match(/nop/))===JSON.stringify(/nop/.exec(str)); //true
//e2 ... e4 //true
e5=JSON.stringify(str.match(/(ab)a/))===JSON.stringify(/(ab)a/.exec(str)); //true

Le .exec () fonction regexp.exec(str)va effectuer les opérations suivantes:

  • s'il est un match , il retourne:
    • si le gdrapeau est utilisé dans l'expression rationnelle: il retournera (à chaque fois qu'il est appelé) : [N_MatchedStr, N_Captured1, N_Captured2, ...]de la prochaine Ncorrespondance. Important: il ne passera pas à la prochaine correspondance si l'objet regexp n'est pas stocké dans une variable (il doit être le même objet)
    • si le gdrapeau n'est pas utilisé dans l'expression rationnelle: il retournera le même que s'il avait un gdrapeau et a été appelé pour la première fois et une seule fois.
  • s'il n'y a pas de correspondance, il retournera:
    • null

Exemple de .exec () (expression rationnelle stockée + en utilisant le gdrapeau = cela change à chaque appel):

var str = "qqqABApppabacccaba";
var myexec, rgxp = /(ab)a/gi;

myexec = rgxp.exec(str);
console.log(myexec); //["ABA", "AB"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "ab"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "ab"]
myexec = rgxp.exec(str);
console.log(myexec); //null

//But in this case you should use a loop:
var mtch, myRe = /(ab)a/gi;
while(mtch = myRe.exec(str)){ //infinite looping with direct regexps: /(ab)a/gi.exec()
    console.log("elm: "+mtch[0]+" all: "+mtch+" indx: "+myRe.lastIndex);
    //1st iteration = elm: "ABA" all: ["ABA", "AB"] indx: 6
    //2nd iteration = elm: "aba" all: ["aba", "ab"] indx: 12
    //3rd iteration = elm: "aba" all: ["aba", "ab"] indx: 18
}

Exemples de .exec () quand il ne change pas à chaque appel:

var str = "qqqABApppabacccaba", myexec, myexec2;

//doesn't go into the next one because no g flag
var rgxp = /(a)(ba)/;
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "a", "ba"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "a", "ba"]
//... ["aba", "a", "ba"]

//doesn't go into the next one because direct regexp
myexec2 = /(ab)a/gi.exec(str);
console.log(myexec2); //["ABA", "AB"]
myexec2 = /(ab)a/gi.exec(str);
console.log(myexec2); //["ABA", "AB"]
//... ["ABA", "AB"]
ajax333221
la source
1

Parfois, regex.exec () prendra beaucoup plus de temps que string.match ().

Il convient de mentionner que si le résultat de string.match () et regex.exec () est le même (ex: si vous n'utilisez pas le drapeau \ g), regex.exec () prendra quelque part entre x2 et x30 puis string. rencontre():

Par conséquent, dans de tels cas, l'utilisation de l'approche de "new RegExp (). Exec ()" ne doit être utilisée que lorsque vous avez besoin d'une expression régulière globale (c'est-à-dire pour s'exécuter plus d'une fois).

Dorony
la source
1
Avez-vous une référence?
Sơn Trần-Nguyễn