Je veux faire correspondre une partie d'une chaîne en utilisant un expression régulière puis accéder à cette sous-chaîne entre parenthèses:
var myString = "something format_abc"; // I want "abc"
var arr = /(?:^|\s)format_(.*?)(?:\s|$)/.exec(myString);
console.log(arr); // Prints: [" format_abc", "abc"] .. so far so good.
console.log(arr[1]); // Prints: undefined (???)
console.log(arr[0]); // Prints: format_undefined (!!!)
Qu'est-ce que je fais mal?
J'ai découvert qu'il n'y avait rien de mal avec le code des expressions rationnelles ci-dessus: la chaîne sur laquelle je testais était la suivante:
"date format_%A"
Signaler que "% A" n'est pas défini semble un comportement très étrange, mais il n'est pas directement lié à cette question. J'en ai donc ouvert un nouveau, Pourquoi une sous-chaîne correspondante renvoie-t-elle "non défini" en JavaScript?.
Le problème était que console.log
prenait ses paramètres comme une instruction printf
, et puisque la chaîne que je consignais ("%A"
) avait une valeur spéciale, elle essayait de trouver la valeur du paramètre suivant.
Vous pouvez accéder aux groupes de capture comme ceci:
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);
}
Voici une méthode que vous pouvez utiliser pour obtenir le groupe de capture n e pour chaque correspondance:
function getMatches(string, regex, index) {
index || (index = 1); // default to the first capturing group
var matches = [];
var match;
while (match = regex.exec(string)) {
matches.Push(match[index]);
}
return matches;
}
// Example :
var myString = 'something format_abc something format_def something format_ghi';
var myRegEx = /(?:^|\s)format_(.*?)(?:\s|$)/g;
// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);
// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);
var myString = "something format_abc";
var arr = myString.match(/\bformat_(.*?)\b/);
console.log(arr[0] + " " + arr[1]);
Le \b
n'est pas exactement la même chose. (Cela fonctionne sur --format_foo/
, mais pas sur format_a_b
) Mais je voulais montrer une alternative à votre expression, ce qui est bien. Bien entendu, l’appel match
est l’important.
En ce qui concerne les exemples de parenthèses multi-correspondances ci-dessus, je cherchais une réponse ici après ne pas obtenir ce que je voulais:
var matches = mystring.match(/(?:neededToMatchButNotWantedInResult)(matchWanted)/igm);
Après avoir examiné les appels de fonction légèrement compliqués avec while et .Push () ci-dessus, je me suis rendu compte que le problème peut être résolu très élégamment avec mystring.replace () à la place (le remplacement n'est PAS le point essentiel, et n'est même pas résolu , l’option d’appel de fonction récursive CLEAN pour le second paramètre est!):
var yourstring = 'something format_abc something format_def something format_ghi';
var matches = [];
yourstring.replace(/format_([^\s]+)/igm, function(m, p1){ matches.Push(p1); } );
Après cela, je ne pense plus jamais pouvoir utiliser .match () presque jamais.
Votre syntaxe n'est probablement pas la meilleure à garder. FF/Gecko définit RegExp comme une extension de Function.
(FF2 est allé aussi loin que typeof(/pattern/) == 'function'
)
Il semble que cela soit spécifique à FF: IE, Opera et Chrome génèrent toutes des exceptions.
Utilisez plutôt l'une des méthodes précédemment mentionnées par d'autres: RegExp#exec
ou String#match
.
Ils offrent les mêmes résultats:
var regex = /(?:^|\s)format_(.*?)(?:\s|$)/;
var input = "something format_abc";
regex(input); //=> [" format_abc", "abc"]
regex.exec(input); //=> [" format_abc", "abc"]
input.match(regex); //=> [" format_abc", "abc"]
Enfin, j’ai trouvé une ligne de code qui me convenait bien (JS ES6):
let reg = /#([\S]+)/igm; // Get hashtags.
let string = 'mi alegría es total! ✌????\n#fiestasdefindeaño #PadreHijo #buenosmomentos #france #paris';
let matches = (string.match(reg) || []).map(e => e.replace(reg, '$1'));
console.log(matches);
Cela retournera:
['fiestasdefindeaño', 'PadreHijo', 'buenosmomentos', 'france', 'paris']
someString.match(regexPattern)
./format_(.*?)/g
, où (.*?)
serait un groupe correspondant.) Ceux-ci résident dans modèles correspondants.Pour accéder aux groupes correspondants, dans chacun des modèles correspondants, vous avez besoin d'une fonction ou de quelque chose de similaire pour effectuer une itération sur le correspondance. Vous pouvez le faire de différentes manières, comme le montrent de nombreuses autres réponses. La plupart des autres réponses utilisent une boucle while pour parcourir tous les motifs correspondants, mais je pense que nous connaissons tous les dangers potentiels de cette approche. Il est nécessaire de faire correspondre une new RegExp()
à la place du modèle lui-même, qui n’a été mentionné que dans un commentaire. Cela est dû au fait que la méthode .exec()
se comporte comme une fonction fonction générateur - elle s’arrête chaque fois qu’une correspondance est trouvée , mais conserve son .lastIndex
pour continuer à partir du prochain appel .exec()
.
Vous trouverez ci-dessous un exemple de fonction searchString
qui retourne une Array
de tous les modèles correspondants, où chaque match
est une Array
avec tous les groupes correspondants contenant. Au lieu d'utiliser une boucle while, j'ai fourni des exemples utilisant à la fois la fonction Array.prototype.map()
et une méthode plus performante - en utilisant une boucle for
- simple.
Celles-ci sont moins performantes puisqu'elles implémentent une boucle forEach
- au lieu de la for
- plus rapide.
// Concise ES6/ES2015 syntax
const searchString =
(string, pattern) =>
string
.match(new RegExp(pattern.source, pattern.flags))
.map(match =>
new RegExp(pattern.source, pattern.flags)
.exec(match));
// Or if you will, with ES5 syntax
function searchString(string, pattern) {
return string
.match(new RegExp(pattern.source, pattern.flags))
.map(match =>
new RegExp(pattern.source, pattern.flags)
.exec(match));
}
let string = "something format_abc",
pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;
let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag
// Performant ES6/ES2015 syntax
const searchString = (string, pattern) => {
let result = [];
const matches = string.match(new RegExp(pattern.source, pattern.flags));
for (let i = 0; i < matches.length; i++) {
result.Push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
}
return result;
};
// Same thing, but with ES5 syntax
function searchString(string, pattern) {
var result = [];
var matches = string.match(new RegExp(pattern.source, pattern.flags));
for (var i = 0; i < matches.length; i++) {
result.Push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
}
return result;
}
let string = "something format_abc",
pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;
let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag
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 fiable que les autres.
Il n'est pas nécessaire d'appeler la méthode exec
! Vous pouvez utiliser la méthode "match" directement sur la chaîne. N'oubliez pas les parenthèses.
var str = "This is cool";
var matches = str.match(/(This is)( cool)$/);
console.log( JSON.stringify(matches) ); // will print ["This is cool","This is"," cool"] or something like that...
La position 0 contient une chaîne avec tous les résultats. La position 1 a le premier match représenté par des parenthèses et la position 2 le deuxième match est isolé entre vos parenthèses Les parenthèses imbriquées sont délicates, alors méfiez-vous!
Un seul support qui n'est pratique que si vous avez une seule paire de parenthèses:
while ( ( match = myRegex.exec( myStr ) ) && matches.Push( match[1] ) ) {};
En utilisant votre code:
console.log(arr[1]); // prints: abc
console.log(arr[0]); // prints: format_abc
Edit: Safari 3, si cela compte.
String#matchAll
(voir la proposition de la phase 3 du 7 décembre 2018 ) simplifie l'accès à tous les groupes de l'objet de correspondance (sachant que le groupe 0 est le groupe entier). correspondance, tandis que les autres groupes correspondent aux groupes de capture du motif):
Avec
matchAll
disponible, vous pouvez éviter la bouclewhile
etexec
avec/g
... À la place, en utilisantmatchAll
, vous récupérez un itérateur que vous pouvez utiliser avec le plus pratiquefor...of
, tableau étendu , ouArray.from()
constructions
Cette méthode génère une sortie similaire à Regex.Matches
en C #, re.finditer
en Python, preg_match_all
en PHP.
Voir une démo de JS (testée dans Google Chrome 73.0.3683.67 (version officielle), bêta (64 bits)):
var myString = "key1:value1, key2-value2!!@key3=value3";
var matches = myString.matchAll(/(\w+)[:=-](\w+)/g);
console.log([...matches]); // All match with capturing group values
Les spectacles console.log([...matches])
Vous pouvez également obtenir une valeur de correspondance ou des valeurs de groupe spécifiques en utilisant
let matchData = "key1:value1, key2-value2!!@key3=value3".matchAll(/(\w+)[:=-](\w+)/g)
var matches = [...matchData]; // Note matchAll result is not re-iterable
console.log(Array.from(matches, m => m[0])); // All match (Group 0) values
// => [ "key1:value1", "key2-value2", "key3=value3" ]
console.log(Array.from(matches, m => m[1])); // All match (Group 1) values
// => [ "key1", "key2", "key3" ]
NOTE: voir les détails de compatibilité du navigateur .
function getMatches(string, regex, index) {
index || (index = 1); // default to the first capturing group
var matches = [];
var match;
while (match = regex.exec(string)) {
matches.Push(match[index]);
}
return matches;
}
// Example :
var myString = 'Rs.200 is Debited to A/c ...2031 on 02-12-14 20:05:49 (Clear Bal Rs.66248.77) AT ATM. TollFree 1800223344 18001024455 (6am-10pm)';
var myRegEx = /clear bal.+?(\d+\.?\d{2})/gi;
// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);
// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);
function getMatches(string, regex, index) {
index || (index = 1); // default to the first capturing group
var matches = [];
var match;
while (match = regex.exec(string)) {
matches.Push(match[index]);
}
return matches;
}
// Example :
var myString = 'something format_abc something format_def something format_ghi';
var myRegEx = /(?:^|\s)format_(.*?)(?:\s|$)/g;
// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);
// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);
Votre code fonctionne pour moi (FF3 sur Mac) même si je suis d'accord avec PhiLo que la regex devrait probablement être
/\bformat_(.*?)\b/
(Mais bien sûr, je ne suis pas sûr car je ne connais pas le contexte de la regex.)
/*Regex function for extracting object from "window.location.search" string.
*/
var search = "?a=3&b=4&c=7"; // Example search string
var getSearchObj = function (searchString) {
var match, key, value, obj = {};
var pattern = /(\w+)=(\w+)/g;
var search = searchString.substr(1); // Remove '?'
while (match = pattern.exec(search)) {
obj[match[0].split('=')[0]] = match[0].split('=')[1];
}
return obj;
};
console.log(getSearchObj(search));
Nous pouvons accéder au groupe correspondant dans une expression régulière en utilisant une barre oblique inverse suivie du numéro du groupe correspondant:
/([a-z])\1/
Dans le code\1 représenté mis en correspondance par le premier groupe ([a-z])
Vous n'avez pas vraiment besoin d'une boucle explicite pour analyser plusieurs correspondances - transmettez une fonction de remplacement comme deuxième argument, comme décrit dans: String.prototype.replace(regex, func)
:
var str = "Our chief weapon is {1}, {0} and {2}!";
var params= ['surprise', 'fear', 'ruthless efficiency'];
var patt = /{([^}]+)}/g;
str=str.replace(patt, function(m0, m1, position){return params[parseInt(m1)];});
document.write(str);
L'argument m0
représente la sous-chaîne correspondante complète {0}
, {1}
, etc. m1
représente le premier groupe correspondant, c'est-à-dire la partie entre parenthèses dans l'expression régulière qui est 0
pour la première correspondance. Et position
est l'index de départ dans la chaîne où le groupe correspondant a été trouvé - inutilisé dans ce cas.
Avec es2018, vous pouvez maintenant String.match()
avec des groupes nommés, ce qui rend votre regex plus explicite sur ce qu’elle essayait de faire.
const url =
'https://stackoverflow.com/questions/432493/how-do-you-access-the-matched-groups-in-a-javascript-regular-expression?some=parameter';
const regex = /(?<protocol>https?):\/\/(?<hostname>[\w-\.]*)\/(?<pathname>[\w-\./]+)\??(?<querystring>.*?)?$/;
const { groups: segments } = url.match(regex);
console.log(segments);
et vous aurez quelque chose comme
{protocole: "https", nom d'hôte: "stackoverflow.com", chemin: "questions/432493/comment-voulez-vous-accéder-aux-groupes-correspondants dans un expression régulière javascript", chaîne de requête: " un paramètre = "}
Obtenir toutes les occurrences du groupe
let m=[], s = "something format_abc format_def format_ghi";
s.replace(/(?:^|\s)format_(.*?)(?:\s|$)/g, (x,y)=> m.Push(y));
console.log(m);