it-swarm.com.de

Wie greifen Sie in einem regulären JavaScript-Ausdruck auf die übereinstimmenden Gruppen zu?

Ich möchte einen Teil einer Zeichenfolge mithilfe eines regulärer Ausdruck abgleichen und dann auf die in Klammern stehende Unterzeichenfolge zugreifen:

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 (!!!)

Was mache ich falsch?


Ich habe festgestellt, dass mit dem Code für reguläre Ausdrücke oben nichts falsch war: Die eigentliche Zeichenfolge, mit der ich testete, lautete folgendermaßen:

"date format_%A"

Wenn Sie melden, dass "% A" undefined ist, scheint dies ein sehr seltsames Verhalten zu sein, das jedoch nicht direkt mit dieser Frage zusammenhängt. Daher habe ich eine neue geöffnet, WARUM GIBT EIN ÜBEREINSTIMMENDER TEILSTRING IN JAVASCRIPT "UNDEFINED" ZURÜCK?.


Das Problem war, dass console.log seine Parameter wie eine printf-Anweisung annimmt, und da die Zeichenfolge, die ich protokollierte ("%A"), einen besonderen Wert hatte, wurde versucht, den Wert des nächsten Parameters zu ermitteln.

1130
nickf

Sie können auf folgende Gruppen zugreifen:

var myString = "something format_abc";
var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
var match = myRegexp.exec(myString);
console.log(match[1]); // abc

Und wenn es mehrere Übereinstimmungen gibt, können Sie sie wiederholen:

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

1437
CMS

Mit dieser Methode können Sie die Erfassungsgruppe n th für jede Übereinstimmung ermitteln:

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

165
Mathias Bynens

var myString = "something format_abc";
var arr = myString.match(/\bformat_(.*?)\b/);
console.log(arr[0] + " " + arr[1]);

Der \b ist nicht genau dasselbe. (Es funktioniert mit --format_foo/, aber nicht mit format_a_b) Aber ich wollte eine Alternative zu Ihrem Ausdruck zeigen, was in Ordnung ist. Natürlich ist der Aufruf match das Wichtigste.

51
PhiLho

In Bezug auf die oben genannten Beispiele für Multi-Match-Klammern suchte ich hier nach einer Antwort, nachdem ich nicht das bekommen hatte, was ich wollte:

var matches = mystring.match(/(?:neededToMatchButNotWantedInResult)(matchWanted)/igm);

Nachdem ich mir die leicht gewundenen Funktionsaufrufe mit while und .Push () oben angesehen hatte, wurde mir klar, dass das Problem mit mystring.replace () sehr elegant gelöst werden kann (das Ersetzen ist NICHT der Punkt und wird nicht einmal gemacht , die CLEAN-Funktion für den rekursiven Funktionsaufruf für den zweiten Parameter ist!):

var yourstring = 'something format_abc something format_def something format_ghi';

var matches = [];
yourstring.replace(/format_([^\s]+)/igm, function(m, p1){ matches.Push(p1); } );

Danach glaube ich nicht, dass ich .match () fast nie wieder verwenden werde.

25
Alexz

Ihre Syntax ist wahrscheinlich nicht die beste zu behalten. FF/Gecko definiert RegExp als eine Erweiterung von Function.
(FF2 ging bis zu typeof(/pattern/) == 'function')

Es scheint, dass dies spezifisch für FF-IE, Opera und Chrome ist, die alle Ausnahmen dafür auslösen.

Verwenden Sie stattdessen eine der zuvor genannten Methoden: RegExp#exec oder String#match.
Sie bieten die gleichen Ergebnisse:

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"]
16

Zu guter Letzt fand ich eine Codezeile, die für mich gut funktionierte (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);

Dies wird zurückkehren:

['fiestasdefindeaño', 'PadreHijo', 'buenosmomentos', 'france', 'paris']
15
Sebastien H.

In dieser Antwort verwendete Terminologie:

  • Match zeigt das Ergebnis der Ausführung Ihres RegEx-Musters anhand Ihrer Zeichenfolge an: someString.match(regexPattern).
  • Matched-Patterns bezeichnen alle übereinstimmenden Teile der Eingabezeichenfolge, die sich alle im match -Array befinden. Dies sind alle Instanzen Ihres Musters in der Eingabezeichenfolge.
  • Übereinstimmende Gruppen geben alle Gruppen an, die im RegEx-Muster definiert werden sollen. (Die Muster in Klammern sind wie folgt: /format_(.*?)/g, wobei (.*?) eine übereinstimmende Gruppe wäre.) Diese befinden sich in übereinstimmenden Mustern.

Beschreibung

Um Zugriff auf die übereinstimmende Gruppen zu erhalten, benötigen Sie in jedem der übereinstimmenden Muster eine Funktion oder etwas Ähnliches, um über die Übereinstimmung zu iterieren. Es gibt verschiedene Möglichkeiten, wie Sie dies tun können, wie viele der anderen Antworten zeigen. Die meisten anderen Antworten verwenden eine while-Schleife, um alle übereinstimmenden Muster zu durchlaufen, aber ich denke, wir alle kennen die potenziellen Gefahren bei diesem Ansatz. Es ist notwendig, mit einem new RegExp() zu vergleichen, und nicht nur mit dem Muster selbst, das nur in einem Kommentar erwähnt wurde. Dies liegt daran, dass sich die .exec()-Methode ähnlich wie eine Generatorfunktionverhält. _ - Sie stoppt jedes Mal, wenn eine Übereinstimmung vorliegt , hält jedoch ihren .lastIndex-Wert für den nächsten .exec()-Aufruf aufrecht.

Codebeispiele

Unten ist ein Beispiel für eine Funktion searchString, die eine Array aller übereinstimmenden Muster zurückgibt, wobei jede match eine Array ist, die alle übereinstimmende Gruppen enthält. Anstatt eine while-Schleife zu verwenden, habe ich Beispiele bereitgestellt, die sowohl die Funktion Array.prototype.map() als auch eine performantere Methode verwenden - eine einfache for-Schleife.

Prägnante Versionen (weniger Code, mehr syntaktischer Zucker)

Diese sind weniger performant, da sie im Grunde eine forEach-Schleife anstelle der schnelleren for-Schleife implementieren.

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

Performante Versionen (mehr Code, weniger syntaktischer Zucker)

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

Ich muss diese Alternativen noch mit den zuvor in den anderen Antworten genannten vergleichen, aber ich bezweifle, dass dieser Ansatz weniger performant und weniger ausfallsicher ist als die anderen.

12
Daniel Hallgren

Die exec-Methode muss nicht aufgerufen werden! Sie können die Methode "match" direkt in der Zeichenfolge verwenden. Vergessen Sie einfach nicht die Klammern.

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

Position 0 enthält eine Zeichenfolge mit allen Ergebnissen. Position 1 hat die erste Übereinstimmung in Klammern und Position 2 die zweite Übereinstimmung in Ihren Klammern. Verschachtelte Klammern sind schwierig, also Vorsicht!

11
Andre Carneiro

Eine Einlage, die nur dann sinnvoll ist, wenn Sie nur ein Paar Klammern haben:

while ( ( match = myRegex.exec( myStr ) ) && matches.Push( match[1] ) ) {};
7
Nabil Kadimi

Verwenden Sie Ihren Code:

console.log(arr[1]);  // prints: abc
console.log(arr[0]);  // prints:  format_abc

Edit: Safari 3, wenn es darauf ankommt.

6
eyelidlessness

String#matchAll (siehe den Stage 3 Draft/7. Dezember 2018-Vorschlag ) vereinfacht den Zugriff auf alle Gruppen im Übereinstimmungsobjekt (bedenken Sie, dass Gruppe 0 die gesamte Übereinstimmung ist, während weiter Gruppen entsprechen den Erfassungsgruppen im Muster):

Wenn matchAll verfügbar ist, können Sie die while-Schleife und exec mit /g... vermeiden. Stattdessen erhalten Sie mit matchAll einen Iterator zurück, den Sie mit dem bequemeren for...of , Array Spread oder verwenden können Array.from() Konstrukte

Diese Methode liefert eine ähnliche Ausgabe wie Regex.Matches in C #, re.finditer in Python, preg_match_all in PHP.

Sehen Sie sich eine JS-Demo an (getestet in Google Chrome 73.0.3683.67 (offizielles Build), Beta (64-Bit)):

var myString = "key1:value1, [email protected]=value3";
var matches = myString.matchAll(/(\w+)[:=-](\w+)/g);
console.log([...matches]); // All match with capturing group values

Die console.log([...matches]) zeigt

 enter image description here

Sie können auch Übereinstimmungswerte oder bestimmte Gruppenwerte mit abrufen

let matchData = "key1:value1, [email protected]=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: Siehe die Browserkompatibilität Details.

5

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

5
Jack

Ihr Code funktioniert für mich (FF3 auf Mac), auch wenn ich mit PhiLo einverstanden bin, dass der Regex wahrscheinlich sein sollte:

/\bformat_(.*?)\b/

(Aber ich bin mir natürlich nicht sicher, weil ich den Kontext der Regex nicht kenne.)

2
PEZ
/*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));
1
Pawel Kwiecien

Wir können auf die übereinstimmende Gruppe in regulären Ausdrücken zugreifen, indem wir einen Backslash gefolgt von der Nummer der übereinstimmenden Gruppe verwenden:

/([a-z])\1/

In dem dargestellten Code\1 entspricht die erste Gruppe ([a-z])

1
Md. A. Barik

Sie benötigen keine explizite Schleife, um mehrere Übereinstimmungen zu analysieren - übergeben Sie eine Ersetzungsfunktion als zweites Argument, wie in: 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);

Das Argument m0 steht für den vollständig übereinstimmenden Teilstring {0}, {1} usw. m1 steht für die erste übereinstimmende Gruppe, dh den in Klammern eingeschlossenen Teil, der 0 für das erste Spiel. Und position ist der Startindex innerhalb der Zeichenfolge, in der die übereinstimmende Gruppe gefunden wurde - in diesem Fall nicht verwendet.

1
ccpizza

Mit es2018 können Sie nun String.match() mit benannten Gruppen machen, wodurch Ihre Regex expliziter wird, was sie tun wollte.

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

und du wirst so etwas bekommen 

{Protokoll: "https", Hostname: "stackoverflow.com", Pfadname: "questions/432493/how-do-you-access-the-matched-groups-in-a-javascript-regular-expression", querystring: " some = parameter "}

0
David Cheung

Alle Gruppenvorkommen abrufen

let m=[], s = "something format_abc  format_def  format_ghi";

s.replace(/(?:^|\s)format_(.*?)(?:\s|$)/g, (x,y)=> m.Push(y));

console.log(m);
0