Question Comment accéder aux groupes correspondants dans une expression régulière JavaScript?


Je veux faire correspondre une partie d'une chaîne en utilisant un expression régulière puis accédez à 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 d'expression régulière ci-dessus: la chaîne que je testais était la suivante:

"date format_%A"

Signaler que "% A" est indéfini semble un comportement très étrange, mais il n'est pas directement lié à cette question, alors j'en ai ouvert un nouveau, Pourquoi une sous-chaîne appariée renvoie-t-elle "indéfini" dans JavaScript?.


Le problème était que console.log prend ses paramètres comme un printf déclaration, et depuis la chaîne que je enregistrais ("%A") avait une valeur spéciale, il essayait de trouver la valeur du paramètre suivant.


1019
2018-01-11 07:21


origine


Réponses:


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);
}


1304
2018-01-11 07:26



Voici une méthode que vous pouvez utiliser pour obtenir le nLe groupe de capture pour chaque match:

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);


152
2018-01-08 08:26



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 ne fonctionne pas format_a_b) Mais je voulais montrer une alternative à votre expression, ce qui est bien. Bien sûr, le match appel est la chose importante.


48
2018-01-11 09:10



En ce qui concerne les exemples de parenthèses multi-match 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 regardé les appels de fonctions légèrement alambiquées 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 intégrée CLEAN pour le deuxième 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 pas que je vais jamais utiliser .match () pour presque rien de plus jamais.


19
2017-07-17 04:53



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 ce soit spécifique à FF - IE, Opera, et Chrome toutes les exceptions de jeter pour elle.

Au lieu de cela, utilisez 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"]

15
2018-01-11 12:55



Dernier point mais non le moindre, j'ai trouvé ce code de ligne qui a bien fonctionné pour moi (JS ES6):

var reg = /#([\S]+)/igm; //get hashtags
var string = 'mi alegría es total! \n#fiestasdefindeaño #PadreHijo #buenosmomentos #france #paris';

var matches = (string.match(reg) || []).map(e => e.replace(reg, '$1'));
console.log(matches);

cela reviendra: [fiestasdefindeaño, PadreHijo, buenosmomentos, france, paris]


9
2018-01-03 14:40



Terminologie utilisée dans cette réponse:

  • Rencontre indique le résultat de l'exécution de votre motif RegEx sur votre chaîne comme suit: someString.match(regexPattern).
  • Motifs assortis indique toutes les parties correspondantes de la chaîne d'entrée, qui résident toutes à rencontre tableau. Ce sont toutes les instances de votre modèle dans la chaîne d'entrée.
  • Groupes appariés indique tous les groupes à attraper, définis dans le modèle RegEx. (Les motifs entre parenthèses, comme ceci: /format_(.*?)/g, où (.*?) serait un groupe apparié.) Ceux-ci résident dans motifs assortis.

La description

Pour avoir accès à la groupes appariés, dans chacun des motifs assortis, vous avez besoin d'une fonction ou quelque chose de similaire à itérer sur le rencontre. Vous pouvez le faire de plusieurs façons, comme le montrent les autres réponses. La plupart des autres réponses utilisent une boucle while pour parcourir tous les motifs assortis, mais je pense que nous connaissons tous les dangers potentiels de cette approche. Il est nécessaire de faire correspondre new RegExp() au lieu de juste le modèle lui-même, qui a seulement été mentionné dans un commentaire. C'est parce que le .exec() méthode se comporte comme un fonction de générateur - il s'arrête chaque fois qu'il y a un matchmais garde ses .lastIndex pour continuer à partir de là le prochain .exec() appel.

Exemples de code

Voici un exemple d'une fonction searchString qui renvoie un Array de tout motifs assortis, où chaque match est un Array avec tout le contenant groupes appariés. Au lieu d'utiliser une boucle while, j'ai fourni des exemples en utilisant à la fois le Array.prototype.map() fonction ainsi que d'une manière plus performante - en utilisant une plaine for-boucle.

Versions concises (moins de code, plus de sucre syntaxique)

Ce sont moins performants car ils mettent en œuvre fondamentalement un forEach-loop au lieu du plus rapide for-boucle.

// 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

Versions performantes (plus de code, moins de sucre syntaxique)

// 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 sûre que les autres.


7
2017-08-23 22:36



Un seul doublage pratique uniquement si vous avez une seule paire de parenthèses:

while ( ( match = myRegex.exec( myStr ) ) && matches.push( match[1] ) ) {};

5
2017-07-12 15:41