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


Ich möchte einen Teil einer Zeichenkette mit a vergleichen regulären Ausdruck und dann auf diese eingeklammerte Teilzeichenfolge 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 obigen Code für den regulären Ausdruck nichts falsch ist: Die tatsächliche Zeichenfolge, gegen die ich getestet habe, war folgende:

"date format_%A"

Die Meldung, dass "% A" nicht definiert ist, scheint ein sehr seltsames Verhalten zu sein, aber es steht nicht direkt mit dieser Frage in Verbindung, also habe ich eine neue geöffnet, Warum gibt eine übereinstimmende Teilzeichenfolge in JavaScript "undefiniert" zurück?.


Das Problem war das console.log nimmt seine Parameter wie a printf Anweisung und seit der Zeichenfolge, die ich protokolliert habe ("%A") hatte einen speziellen Wert, es wurde versucht, den Wert des nächsten Parameters zu finden.


1019
2018-01-11 07:21


Ursprung


Antworten:


Sie können auf Erfassungsgruppen wie folgt 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 über sie iterieren:

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



Hier ist eine Methode, die Sie verwenden können, um die nDie fangende Gruppe für jedes Spiel:

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

Das \b ist nicht genau dasselbe. (Es funktioniert auf --format_foo/, funktioniert aber nicht format_a_b) Aber ich wollte eine Alternative zu deinem Ausdruck zeigen, was in Ordnung ist. Natürlich, die match Anruf ist das Wichtigste.


48
2018-01-11 09:10



In Bezug auf die obigen Beispiele für mehrere zusammenpassende Klammern habe ich nach einer Antwort gesucht, nachdem ich nicht bekommen habe, was ich wollte:

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

Nach dem Betrachten der leicht gewundenen Funktionsaufrufe mit while und .push () oben, dämmerte es mir, dass das Problem sehr elegant mit mystring.replace () gelöst werden kann (das Ersetzen ist NICHT der Punkt und ist noch nicht einmal erledigt) , die CLEAN, integrierte rekursive Funktionsaufrufoption 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 denke ich nicht, dass ich .match () für fast alles jemals wieder verwenden werde.


19
2017-07-17 04:53



Ihre Syntax ist wahrscheinlich nicht die beste, um sie 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 ist - IE, Opera und Chrome werfen alle Ausnahmen dafür.

Verwenden Sie stattdessen eine der zuvor erwähnten 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"]

15
2018-01-11 12:55



Zu guter Letzt fand ich einen Zeilencode, der für mich funktionierte (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);

Das wird zurückkehren: [fiestasdefindeaño, PadreHijo, buenosmomentos, france, paris]


9
2018-01-03 14:40



Terminologie in dieser Antwort verwendet:

  • Spiel zeigt das Ergebnis der Ausführung Ihres RegEx-Musters wie folgt an: someString.match(regexPattern).
  • Abgestimmte Muster Geben Sie alle übereinstimmenden Teile der Eingabezeichenfolge an, die alle in der Spiel Array. Dies sind alle Instanzen Ihres Musters innerhalb der Eingabezeichenfolge.
  • Abgestimmte Gruppen Geben Sie alle zu erfassenden Gruppen an, die im RegEx-Muster definiert sind. (Die Muster in Klammern, wie folgt: /format_(.*?)/g, woher (.*?) wäre eine passende Gruppe.) Diese befinden sich in übereinstimmende Muster.

Beschreibung

Um Zugriff auf die übereinstimmende Gruppenin jedem der übereinstimmende Muster, Sie benötigen eine Funktion oder etwas Ähnliches, um über die zu iterieren Spiel. Es gibt eine Reihe von Möglichkeiten, wie Sie dies tun können, wie viele der anderen Antworten zeigen. Die meisten anderen Antworten verwenden eine while-Schleife, um über alle zu iterieren übereinstimmende MusterAber ich denke, wir alle kennen die potenziellen Gefahren bei diesem Ansatz. Es ist notwendig, gegen a zu passen new RegExp() statt nur das Muster selbst, das nur in einem Kommentar erwähnt wurde. Dies ist, weil die .exec() Methode verhält sich ähnlich wie a Generatorfunktion - es stoppt jedes Mal, wenn es ein Spiel gibt, aber behält seine .lastIndex von dort auf dem nächsten fortfahren .exec() Anruf.

Codebeispiele

Unten ist ein Beispiel für eine Funktion searchString was einen zurückgibt Array von allen übereinstimmende Muster, wo jeder match ist ein Array mit allem was dazugehört übereinstimmende Gruppen. Anstatt eine while - Schleife zu verwenden, habe ich Beispiele mit beiden gegeben Array.prototype.map() Funktion sowie eine leistungsfähigere Art und Weise - mit einer Ebene for-Schleife.

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

Diese sind weniger performant, da sie grundsätzlich a forEach-loop statt der schneller for-Schleife.

// 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 erwähnten vergleichen, aber ich bezweifle, dass dieser Ansatz weniger leistungsfähig und weniger ausfallsicher ist als die anderen.


7
2017-08-23 22:36