Vous pouvez accéder à des groupes de capture comme celui-ci:
var myString = "something format_abc";
var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
var match = myRegexp.exec(myString);
console.log(match[1]); // abc
Et s'il y a plusieurs correspondances, vous pouvez les parcourir:
var myString = "something format_abc";
var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
match = myRegexp.exec(myString);
while (match != null) {
// matched text: match[0]
// match start: match.index
// capturing group n: match[n]
console.log(match[0])
match = myRegexp.exec(myString);
}
Modifier: 2019-09-10
Comme vous pouvez le voir, la manière d'itérer sur plusieurs correspondances n'était pas très intuitive. Cela a conduit à la proposition de la String.prototype.matchAll
méthode. Cette nouvelle méthode devrait être livrée dans la spécification ECMAScript 2020 . Il nous donne une API propre et résout plusieurs problèmes. Il a commencé à atterrir sur les principaux navigateurs et moteurs JS comme Chrome 73+ / Node 12+ et Firefox 67+.
La méthode renvoie un itérateur et est utilisée comme suit:
const string = "something format_abc";
const regexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
const matches = string.matchAll(regexp);
for (const match of matches) {
console.log(match);
console.log(match.index)
}
Comme il retourne un itérateur, nous pouvons dire qu'il est paresseux, cela est utile lors de la manipulation d'un nombre particulièrement important de groupes de capture ou de très grandes chaînes. Mais si vous en avez besoin, le résultat peut être facilement transformé en tableau en utilisant la syntaxe étalée ou la Array.from
méthode:
function getFirstGroup(regexp, str) {
const array = [...str.matchAll(regexp)];
return array.map(m => m[1]);
}
// or:
function getFirstGroup(regexp, str) {
return Array.from(str.matchAll(regexp), m => m[1]);
}
En attendant, bien que cette proposition bénéficie d'un support plus large, vous pouvez utiliser le package shim officiel .
De plus, le fonctionnement interne de la méthode est simple. Une implémentation équivalente utilisant une fonction de générateur serait la suivante:
function* matchAll(str, regexp) {
const flags = regexp.global ? regexp.flags : regexp.flags + "g";
const re = new RegExp(regexp, flags);
let match;
while (match = re.exec(str)) {
yield match;
}
}
Une copie de l'expression rationnelle d'origine est créée; ceci afin d'éviter les effets secondaires dus à la mutation de la lastIndex
propriété lors du passage par les correspondances multiples.
De plus, nous devons nous assurer que l'expression rationnelle a le drapeau global pour éviter une boucle infinie.
Je suis également heureux de voir que même cette question StackOverflow a été référencée dans les discussions sur la proposition .
var match = myString.match(myRegexp); // alert(match[1])
:?string = string.substring(match.index + match[0].length)
Voici une méthode que vous pouvez utiliser pour obtenir le n ème groupe de capture pour chaque correspondance:
la source
Ce
\b
n'est pas exactement la même chose. (Cela fonctionne--format_foo/
, mais ne fonctionne pasformat_a_b
) Mais je voulais montrer une alternative à votre expression, ce qui est bien. Bien sûr, l'match
appel est la chose importante.la source
format_a_b
" comme une réflexion après il y a 6 ans, et je ne me souviens pas de ce que je voulais dire là-bas ... :-) Je suppose que cela signifiait "ne fonctionne pas pour capturera
uniquement", c'est à dire. la première partie alphabétique aprèsformat_
.En ce qui concerne les exemples de parenthèses multi-correspondance ci-dessus, je cherchais une réponse ici après ne pas avoir obtenu ce que je voulais:
Après avoir regardé les appels de fonction légèrement alambiqués avec while et .push () ci-dessus, il m'est apparu que le problème peut être résolu très élégamment avec mystring.replace () à la place (le remplacement n'est PAS le point, et n'est même pas fait , l'option d'appel de fonction récursive CLEAN intégrée pour le deuxième paramètre est!):
Après cela, je ne pense pas que j'utiliserai jamais .match () pour presque rien.
la source
Enfin, j'ai trouvé une ligne de code qui fonctionnait bien pour moi (JS ES6):
Cela reviendra:
la source
replace
approche complète d'Alexz parce que celle-ci est moins prospective et plus élégante pour plusieurs résultats. Bon travail là-dessus, Sébastien H.Terminologie utilisée dans cette réponse:
someString.match(regexPattern)
./format_(.*?)/g
où(.*?)
serait un groupe correspondant.) Ceux-ci résident dans des modèles correspondants .La description
Pour accéder aux groupes correspondants , dans chacun des modèles correspondants , vous avez besoin d'une fonction ou quelque chose de similaire pour itérer sur la correspondance . Il existe plusieurs façons de procéder, comme le montrent la plupart des autres réponses. La plupart des autres réponses utilisent une boucle while pour parcourir tous les modèles correspondants , mais je pense que nous connaissons tous les dangers potentiels de cette approche. Il est nécessaire de faire correspondre un
new RegExp()
au lieu d'un simple motif lui-même, qui n'a été mentionné que dans un commentaire. Cela est dû au fait que la.exec()
méthode se comporte de manière similaire à une fonction de générateur - elle s'arrête à chaque fois qu'il y a une correspondance , mais continue.lastIndex
de continuer à partir de là lors du prochain.exec()
appel.Exemples de code
Ci-dessous est un exemple de fonction
searchString
qui renvoie unArray
de tous les modèles correspondants , où chacunmatch
est unArray
avec tous les groupes correspondants contenant . Au lieu d'utiliser une boucle while, j'ai fourni des exemples utilisant à la fois laArray.prototype.map()
fonction et une manière plus performante - en utilisant unefor
boucle simple .Versions concises (moins de code, plus de sucre syntaxique)
Celles-ci sont moins performantes car elles implémentent fondamentalement un
forEach
-loop au lieu dufor
-loop plus rapide.Versions performantes (plus de code, moins de sucre syntaxique)
Je n'ai pas encore comparé ces alternatives à celles mentionnées précédemment dans les autres réponses, mais je doute que cette approche soit moins performante et moins sûre que les autres.
la source
String#matchAll
(voir la proposition de l' étape 3 / proposition du 7 décembre 2018 ), simplifie l'accès à tous les groupes dans l'objet de correspondance (sachez que le groupe 0 est la correspondance complète, tandis que d'autres groupes correspondent aux groupes de capture dans le modèle):Cette méthode donne une sortie similaire à
Regex.Matches
C #,re.finditer
en Python,preg_match_all
en PHP.Voir une démo JS (testée dans Google Chrome 73.0.3683.67 (version officielle), bêta (64 bits)):
Les
console.log([...matches])
spectaclesVous pouvez également obtenir une valeur de correspondance ou des valeurs de groupe spécifiques en utilisant
REMARQUE : voir les détails de compatibilité du navigateur .
la source
Votre syntaxe n'est probablement pas la meilleure à conserver. FF / Gecko définit RegExp comme une extension de Function.
(FF2 est allé jusqu'à
typeof(/pattern/) == 'function'
)Il semble que cela soit spécifique à FF-IE, Opera et Chrome, tous lèvent des exceptions pour cela.
À la place, utilisez l'une des méthodes précédemment mentionnées par d'autres:
RegExp#exec
ouString#match
.Ils offrent les mêmes résultats:
la source
Il n'est pas nécessaire d'invoquer la
exec
méthode! Vous pouvez utiliser la méthode "match" directement sur la chaîne. N'oubliez pas les parenthèses.La position 0 a une chaîne avec tous les résultats. La position 1 a la première correspondance représentée par des parenthèses, et la position 2 a la deuxième correspondance isolée entre vos parenthèses. Les parenthèses imbriquées sont délicates, alors méfiez-vous!
la source
Une doublure pratique uniquement si vous avez une seule paire de parenthèses:
la source
while (match = myRegex.exec(myStr)) matches.push(match[1])
En utilisant votre code:
Edit: Safari 3, si c'est important.
la source
Avec es2018, vous pouvez désormais
String.match()
avec des groupes nommés, rendre votre expression rationnelle plus explicite de ce qu'elle essayait de faire.et vous obtiendrez quelque chose comme
la source
la source
Votre code fonctionne pour moi (FF3 sur Mac) même si je suis d'accord avec PhiLo que le regex devrait probablement être:
(Mais, bien sûr, je ne suis pas sûr car je ne connais pas le contexte de l'expression régulière.)
la source
la source
Vous n'avez pas vraiment besoin d'une boucle explicite pour analyser plusieurs correspondances - passez une fonction de remplacement comme deuxième argument comme décrit dans
String.prototype.replace(regex, func)
::L'
m0
argument représente la sous{0}
- chaîne entièrement mise en correspondance{1}
, etc.m1
représente le premier groupe de correspondance, c'est-à-dire la partie entre crochets dans l'expression régulière qui correspond0
à la première correspondance. Etposition
est l'index de départ dans la chaîne où le groupe correspondant a été trouvé - inutilisé dans ce cas.la source
Dans le code \ 1 représenté correspond au premier groupe ([az])
la source
Solution en une ligne:
Vous pouvez donc utiliser cette méthode (doit utiliser / g):
résultat:
la source
Obtenir toutes les occurrences de groupe
la source
Si vous êtes comme moi et que vous souhaitez que regex renvoie un objet comme celui-ci:
puis coupez la fonction d'en bas
la source
UTILISATION JUSTE RegExp. $ 1 ... $ n e groupe par exemple:
1.Pour correspondre au 1er groupe RegExp. $ 1
si vous utilisez 3 groupes dans regex likey (notez l'utilisation après string.match (regex))
RegExp. $ 1 RegExp. $ 2 RegExp. $ 3
la source