Terminologia użyta w tej odpowiedzi:
- Mecz wskazuje wynik prowadzenie wzór regex przeciw ciąg tak:
someString.match(regexPattern)
.
- Dopasowane wzorce wskazują wszystkie pasujące części ciągu wejściowego, które wszystkie znajdują się w tablicy dopasowania . Są to wszystkie wystąpienia wzorca w ciągu wejściowym.
- Dopasowane grupy wskazują wszystkie grupy do złapania, zdefiniowane we wzorze RegEx. (Wzory w nawiasach, takie jak:,
/format_(.*?)/g
gdzie (.*?)
byłaby dopasowana grupa.) Znajdują się one w dopasowanych wzorach .
Opis
Aby uzyskać dostęp do dopasowanych grup , w każdym dopasowanym wzorcu potrzebujesz funkcji lub czegoś podobnego do iteracji po dopasowaniu . Istnieje wiele sposobów, aby to zrobić, jak pokazuje wiele innych odpowiedzi. Większość innych odpowiedzi wykorzystuje pętlę while do iteracji wszystkich dopasowanych wzorców , ale myślę, że wszyscy znamy potencjalne niebezpieczeństwa związane z takim podejściem. Konieczne jest dopasowanie do new RegExp()
samego wzorca, o którym wspomniano tylko w komentarzu. Wynika to z faktu, że .exec()
metoda zachowuje się podobnie do funkcji generatora - zatrzymuje się za każdym razem, gdy występuje dopasowanie , ale .lastIndex
kontynuuje ją od następnego .exec()
wywołania.
Przykłady kodu
Poniżej znajduje się przykład funkcję searchString
, która zwraca Array
na wszystkich dopasowanych wzorców , gdzie każdy match
oznacza Array
ze wszystkie zawierającego grupy dopasowane . Zamiast używać pętli while, podałem przykłady, używając zarówno Array.prototype.map()
funkcji, jak i bardziej wydajnego sposobu - używając zwykłej for
pętli.
Zwięzłe wersje (mniej kodu, więcej cukru syntaktycznego)
Są one mniej wydajne, ponieważ w zasadzie implementują forEach
pętlę zamiast szybszej for
pętli.
// 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
Wersje performanckie (więcej kodu, mniej cukru syntaktycznego)
// 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
Muszę jeszcze porównać te alternatywy z poprzednio wymienionymi w innych odpowiedziach, ale wątpię, aby to podejście było mniej wydajne i mniej bezpieczne w przypadku awarii niż inne.