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.
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);
}
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);
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.
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.
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"]
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']
someString.match(regexPattern)
./format_(.*?)/g
, wobei (.*?)
eine übereinstimmende Gruppe wäre.) Diese befinden sich in übereinstimmenden Mustern.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.
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.
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
// 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.
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!
Eine Einlage, die nur dann sinnvoll ist, wenn Sie nur ein Paar Klammern haben:
while ( ( match = myRegex.exec( myStr ) ) && matches.Push( match[1] ) ) {};
Verwenden Sie Ihren Code:
console.log(arr[1]); // prints: abc
console.log(arr[0]); // prints: format_abc
Edit: Safari 3, wenn es darauf ankommt.
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 diewhile
-Schleife undexec
mit/g
... vermeiden. Stattdessen erhalten Sie mitmatchAll
einen Iterator zurück, den Sie mit dem bequemerenfor...of
, Array Spread oder verwenden könnenArray.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
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.
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);
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.)
/*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));
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])
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.
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 "}
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);