Как получить доступ к совпадающим группам в регулярном выражении JavaScript?

Я хочу сопоставить часть строки с помощью регулярное выражение, а затем получить доступ к этой подстроке в скобках:

var myString = "something format_abc"; // I want "abc"

var arr = /(?:^|\s)format_(.*?)(?:\s|$)/.exec(myString);

console.info(arr);     // Prints: [" format_abc", "abc"] .. so far so good.
console.info(arr[1]);  // Prints: undefined  (???)
console.info(arr[0]);  // Prints: format_undefined (!!!)

Что я делаю неправильно?


Я обнаружил, что в приведенном выше коде регулярного выражения нет ничего плохого: фактическая строка, которую я тестировал, была следующей:

"date format_%A"

Сообщение о том, что «% A» не определено, кажется очень странным поведением, но оно не имеет прямого отношения к этому вопросу, поэтому я открыл новый, Почему совпадающая подстрока возвращает "undefined" в JavaScript?.


Проблема заключалась в том, что console.info принимает свои параметры как оператор printf, и поскольку строка, которую я записывала ("%A"), имела особое значение, он пытался найти значение следующего параметра.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1 482
0
839 617
22
Перейти к ответу Данный вопрос помечен как решенный

Ответы 22

Ответ принят как подходящий

Вы можете получить доступ к группам захвата следующим образом:

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

И если есть несколько совпадений, вы можете перебрать их:

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.info(match[0])
  match = myRegexp.exec(myString);
}

Обновлено: 2019-09-10

Как видите, способ перебора нескольких совпадений был не очень интуитивно понятным. Это привело к предложению метода String.prototype.matchAll. Ожидается, что этот новый метод будет отправлен в Спецификация ECMAScript 2020. Это дает нам чистый API и решает множество проблем. Он начал работать в основных браузерах и JS-движках, таких как Chrome 73+ / Node 12+ и Firefox 67+.

Метод возвращает итератор и используется следующим образом:

const string = "something format_abc";
const regexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
const matches = string.matchAll(regexp);
    
for (const match of matches) {
  console.info(match);
  console.info(match.index)
}

Поскольку он возвращает итератор, мы можем сказать, что он ленив, это полезно при обработке особенно большого количества групп захвата или очень больших строк. Но при необходимости результат можно легко преобразовать в массив с помощью метода синтаксис распространения или Array.from:

function getFirstGroup(regexp, str) {
  const array = [...str.matchAll(regexp)];
  return array.map(m => m[1]);
}

// or:
function getFirstGroup(regexp, str) {
  return Array.from(str.matchAll(regexp), m => m[1]);
}

Между тем, пока это предложение получит более широкую поддержку, вы можете использовать официальный пакет прокладок.

Кроме того, внутренняя работа метода проста. Эквивалентная реализация с использованием функции генератора будет следующей:

function* matchAll(str, regexp) {
  const flags = regexp.global ? regexp.flags : regexp.flags + "g";
  const re = new RegExp(regexp, flags);
  let match;
  while (match = re.exec(str)) {
    yield match;
  }
}

Создается копия исходного регулярного выражения; это сделано для того, чтобы избежать побочных эффектов из-за мутации свойства lastIndex при прохождении нескольких совпадений.

Кроме того, нам нужно убедиться, что в регулярном выражении есть флаг Глобальный, чтобы избежать бесконечного цикла.

Я также рад видеть, что даже этот вопрос StackOverflow упоминается в обсуждение предложения.

+1 Обратите внимание, что во втором примере вы должны использовать объект RegExp (не только "/ myregexp /"), потому что он сохраняет значение lastIndex в объекте. Без использования объекта Regexp он будет повторяться бесконечно

ianaz 28.08.2012 16:06

@ianaz: Я не верю, что это правда? По крайней мере, http://jsfiddle.net/weEg9/ работает в Chrome.

spinningarrow 16.10.2012 11:26

Почему вместо: var match = myString.match(myRegexp); // alert(match[1])?

JohnAllen 30.12.2013 21:39

Нет необходимости в явном "новом регулярном выражении", однако бесконечный цикл будет происходить, если не указано / g.

George C 06.06.2014 22:33

Другой способ не попасть в бесконечный цикл - это явно обновить строку, например. string = string.substring(match.index + match[0].length)

Olga 11.02.2016 14:28

@JohnAllen, один допустимый случай использования RegExp.exec вместо String.match - это когда вам нужно получить доступ к подгруппам.

Anis 09.05.2017 20:41

Я не понимаю, почему вы просто не пишете что-то вроде while( match = myRegexp.exec(myString)) {console.info(match[0])})

AturSams 25.05.2017 16:31

точка этого ответа: используйте .exec () и заключите свои группы в квадратные скобки () в шаблоне

Andrew 28.12.2017 22:06
match[0] не является подгруппой регулярных выражений, это первое совпадение в строке. Если вам нужно получить доступ к группам захвата из более подробного регулярного выражения, это причина, по которой вы должны использовать exec.
1nfiniti 11.09.2018 19:49

Пример итерации можно сократить (удалив предыдущее присвоение) с помощью do while, например: do { let match = myRegexp.exec(myString); console.info(match[0]) } while (match != null);

Gustavo6046 08.11.2018 05:23

Я не понимаю, что match[i] для String.prototype.match() ДОЛЖЕН предоставить вам соответствующую группу по индексу i в соответствии с документацией на developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…, но почему-то это не так (по крайней мере, не для меня в Firefox 56)

Ben Philipp 24.12.2018 10:44

См. Официальный MDN (первый пример), чтобы узнать, как преобразовать в массив, затем используйте map (m => m [1]), чтобы получить преобразование одной строки в результат группы совпадений developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

mattdlockyer 28.10.2019 19:24

Я могу сделать console.info(match.index), но как мне сделать console.info(match.0), чтобы получить возвращенный текст (и, следовательно, его длину)? По крайней мере, так это показывает консоль Firefox.

Rodrigo 03.11.2020 02:56

Нашел: console.info(match['0']) или console.info(match[0])

Rodrigo 03.11.2020 03:01

Используя ваш код:

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

Обновлено: Safari 3, если это важно.

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

\b - это не совсем то же самое. (Он работает на --format_foo/, но не работает на format_a_b) Но я хотел показать альтернативу вашему выражению, и это нормально. Конечно, звонок match - это важная вещь.

Все ровно наоборот. '\ b' разделяет слова. слово = '\ w' = [a-zA-Z0-9_]. «формат_а_б» - это слово.

B.F. 23.04.2015 00:09

@BF Честно говоря, я добавил, что "не работает на format_a_b" после размышлений 6 лет назад, и я не помню, что я имел в виду ... :-) Я полагаю, это означало, что "не работает для захвата a" только ", т.е. первая часть по алфавиту после format_.

PhiLho 23.04.2015 10:41

Я хотел сказать, что \ b (- format_foo /} \ b не возвращает "--format_foo /", потому что "-" и "/" не являются символами \ word. Но \ b (format_a_b) \ b действительно возвращает "format_a_b ". Верно? Я имею в виду ваше текстовое заявление в круглых скобках. (Голосов против!)

B.F. 23.04.2015 13:43

Ваш код работает для меня (FF3 на Mac), даже если я согласен с PhiLo, что регулярное выражение, вероятно, должно быть:

/\bformat_(.*?)\b/

(Но, конечно, я не уверен, потому что не знаю контекста регулярного выражения.)

это список, разделенный пробелами, поэтому я подумал, что \ s будет в порядке. странно, что этот код у меня не работал (FF3 Vista)

nickf 11.01.2009 15:04

Да, действительно странно. Вы пробовали это самостоятельно в консоли Firebug? Я имею в виду с пустой страницы.

PEZ 11.01.2009 15:21

Ваш синтаксис, вероятно, не самый лучший для сохранения. FF / Gecko определяет RegExp как расширение Function.
(FF2 дошел до typeof(/pattern/) == 'function')

Кажется, это характерно для FF - IE, Opera и Chrome все выдают исключения для него.

Вместо этого используйте любой метод, ранее упомянутый другими: RegExp#exec или String#match.
Они предлагают те же результаты:

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

Вот метод, который вы можете использовать для получения группы захвата п для каждого совпадения:

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.info(matches);

Это намного лучший ответ по сравнению с другими, потому что он правильно показывает итерацию по всем совпадениям, а не только одно.

Rob Evans 11.05.2013 16:08

mnn прав. Это приведет к бесконечному циклу, если флаг «g» отсутствует. Будьте очень осторожны с этой функцией.

Druska 04.09.2013 22:45

Я улучшил это, чтобы сделать его похожим на re.findall () python. Он группирует все совпадения в массив массивов. Он также устраняет проблему бесконечного цикла глобального модификатора. jsfiddle.net/ravishi/MbwpV

ravishi 22.11.2013 00:00

Есть хороший способ избежать бесконечных циклов while: не используйте их :) Вот хороший пример, в котором мы ограничиваем количество совпадений максимум до 10 000: _OUT_: for (i = 0; i <10000; i ++) { list = regex.exec (строка); if (list === null) {break _OUT_; }; match_list.push (список [индекс]);}

Michael Mikowski 04.07.2014 00:36

@MichaelMikowski теперь вы только что скрыли свой бесконечный цикл, но ваш код будет работать медленно. Я бы сказал, что лучше иметь плохой разрыв кода, чтобы вы его поймали в процессе разработки. Вводить некоторые максимальные итерации bs неаккуратно. Скрытие проблем вместо устранения их первопричин - не решение.

wallacer 29.10.2014 21:34

@wallacer: Я пропустил это в своем последнем пункте в моем последнем посте: 5. Код может и должен выдавать предупреждение, если цикл завершается без перерыва. Это подчеркивает проблему без нарушения кода. И это совсем не "неряшливо".

Michael Mikowski 12.11.2014 02:09

@MichaelMikowski, который не будет значительно медленнее, когда вы не достигнете предела выполнения. Когда вы находитесь, это явно намного медленнее. Я не говорю, что ваш код не работает, я говорю, что на практике я думаю, что он принесет больше вреда, чем пользы. Люди, работающие в среде разработки, увидят, что код работает нормально без нагрузки, несмотря на выполнение 10 000 ненужных выполнений некоторого фрагмента кода. Затем они отправят его в производственную среду и зададутся вопросом, почему их приложение выходит из строя под нагрузкой. По моему опыту, лучше, если что-то сломается очевидным образом и на более раннем этапе цикла разработки.

wallacer 13.11.2014 02:44

@wallacer Конечно, код работает медленнее, когда вы достигаете предела выполнения, но именно поэтому вы выдаете предупреждение (или даже исключение), когда этот случай возникает во время разработки. Но когда вы переходите в производство, код становится намного более надежным. Это похоже на использование setInterval vs. setTimout. Я советую никогда не использовать setInterval, потому что это опасная конструкция по своей сути. Вместо этого используйте setTimeout и при необходимости вызывайте саму процедуру.

Michael Mikowski 13.11.2014 22:11

@wallacer вот еще один пример: я пропатчил uglify-js для внутреннего использования. В mangler раньше был цикл while для выбора уникальных ключей, но он превращался в бесконечный цикл, когда уникальный ключ не мог быть найден. В результате его рефакторинга ограничен поиск до 1000 циклов, и если он все еще не может найти уникальный ключ, он имеет следующий код: throw 'Не удается найти уникальный ключ после 1000 итераций' ;. Теперь он явно терпит неудачу, вместо того, чтобы бесконечно зацикливаться.

Michael Mikowski 13.11.2014 22:17

@MichaelMikowski просто копался в моих старых комментариях и увидел, что я никогда не отвечал здесь. Конечно, в худшем случае использование максимального числа итераций прерывания для предотвращения цикла и очевидный сбой лучше, чем ничего. Во-первых, как насчет того, чтобы взглянуть на реальный алгоритм и выяснить, почему он не завершается, и можно ли изменить его, чтобы он всегда выполнялся. Бесконечные циклы являются признаком плохой конструкции алгоритма, и почти во всех случаях есть лучшее решение, чем «сломаться, если мы попробовали слишком много раз». Это ленивый взлом. Есть места наверняка, но это не рекомендуемое решение в целом

wallacer 07.07.2015 03:11

@MichaelMikowski, и основная проблема, с которой я столкнулся с вашим первоначальным комментарием, - это просто отсутствие производительности под нагрузкой и тот факт, что он умалчивает об этом. Выбрасывать исключение вместо прерывания - это хорошо, поэтому вы поймете проблему. Пример исправления uglify полностью игнорирует основную проблему - загрузку. Если код никогда не будет запускаться под нагрузкой, кого это волнует. Если он работает в nodeJS в сильно загруженной системе, это имеет значение. Многие люди в SO просто слепо копируют код, который они находят, поэтому я подумал, что стоит немного предостеречь ...

wallacer 07.07.2015 03:17

@wallecer Я думаю, что мы согласны со всеми лучшими практиками. Я просто думаю, что следует избегать бесконечных условий цикла, если вы вообще можете. Вместо использования setInterval используйте, например, setTimeout. Или используйте цикл for вместо цикла while. И да, изменение Uglify - уродливое и очень недорогое решение. У меня нет времени на то, чтобы сделать код более правильным, да и затрат на это не стоит. Теперь, если бы я обслуживал миллиарды запросов с кодом, то, конечно, это изменилось бы :)

Michael Mikowski 01.08.2015 01:02

Один лайнер, который практичен только в том случае, если у вас есть одна пара круглых скобок:

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

Почему не while (match = myRegex.exec(myStr)) matches.push(match[1])

willlma 06.04.2017 21:44

Что касается приведенных выше примеров с несколькими совпадениями круглых скобок, я искал здесь ответ после того, как не получил то, от чего хотел:

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

Посмотрев на несколько запутанные вызовы функций с помощью while и .push () выше, меня осенило, что проблема может быть решена очень элегантно с помощью mystring.replace () вместо этого (замена НЕ является сутью и даже не выполняется , опция CLEAN, встроенная рекурсивная функция вызова для второго параметра равна!):

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

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

После этого я не думаю, что когда-нибудь снова буду использовать .match () для чего-нибудь еще.

/*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.info(getSearchObj(search));

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.info(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.info(matches);

И последнее, но не менее важное: я нашел одну строку кода, которая у меня отлично сработала (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.info(matches);

Это вернет:

['fiestasdefindeaño', 'PadreHijo', 'buenosmomentos', 'france', 'paris']
БУМ! Это самое элегантное решение в. Я обнаружил, что это лучше, чем полноценный подход Alexz к replace, потому что он менее дальновиден и более элегантен для множественных результатов. Хорошая работа, Себастьен Х.
Cody 05.05.2020 22:17

Это работает так хорошо, что его определенно входит в мои утилиты :)

Cody 05.05.2020 22:21

Это намного лучше, чем другие ответы! Спасибо!

Owen Versteeg 22.02.2021 23:34

Нет необходимости вызывать метод exec! Вы можете использовать метод "match" непосредственно в строке. Только не забывайте круглые скобки.

var str = "This is cool";
var matches = str.match(/(This is)( cool)$/);
console.info( JSON.stringify(matches) ); // will print ["This is cool","This is"," cool"] or something like that...

Позиция 0 содержит строку со всеми результатами. Позиция 1 содержит первое совпадение, представленное круглыми скобками, а позиция 2 содержит второе совпадение, выделенное в скобках. Вложенные круглые скобки сложны, поэтому будьте осторожны!

Без глобального флага он возвращает все совпадения, с ним вы получите только один большой, так что будьте осторожны.

Shadymilkman01 14.09.2018 01:00

Терминология, использованная в этом ответе:

  • Матч указывает результат выполнения вашего шаблона RegEx для вашей строки, например: someString.match(regexPattern).
  • Соответствующие шаблоны указывают все совпадающие части входной строки, которые все находятся внутри массива матч. Это все экземпляры вашего шаблона внутри входной строки.
  • Соответствующие группы указывают все группы для перехвата, определенные в шаблоне RegEx. (Шаблоны в круглых скобках, например: /format_(.*?)/g, где (.*?) будет совпадающей группой.) Они находятся в совпадающие образцы.

Описание

Чтобы получить доступ к согласованные группы, в каждом из совпадающие образцы вам нужна функция или что-то подобное для итерации по матч. Как показывают многие другие ответы, вы можете сделать это несколькими способами. В большинстве других ответов используется цикл while для перебора всего совпадающие образцы, но я думаю, что все мы знаем потенциальные опасности этого подхода. Это необходимо для сопоставления с new RegExp(), а не только с шаблоном, который упоминается только в комментариях. Это связано с тем, что метод .exec() ведет себя аналогично функция генератора - он останавливается каждый раз, когда есть совпадение, но сохраняет свой .lastIndex для продолжения оттуда при следующем вызове .exec().

Примеры кода

Ниже приведен пример функции searchString, которая возвращает Array всех совпадающие образцы, где каждый match является Array со всеми содержащими согласованные группы. Вместо использования цикла while я привел примеры с использованием как функции Array.prototype.map(), так и более производительного способа - использования простого цикла for.

Краткие версии (меньше кода, больше синтаксического сахара)

Они менее производительны, поскольку в основном реализуют цикл forEach вместо более быстрого цикла for.

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

Мне еще предстоит сравнить эти альтернативы с теми, которые ранее упоминались в других ответах, но я сомневаюсь, что этот подход менее эффективен и менее надежен, чем другие.

С es2018 теперь вы можете String.match() с именованными группами, что делает ваше регулярное выражение более явным для того, что оно пытается сделать.

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.info(segments);

и вы получите что-то вроде

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

На самом деле вам не нужен явный цикл для анализа нескольких совпадений - передайте функцию замены в качестве второго аргумента, как описано в: 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);

Аргумент m0 представляет собой полностью совпавшую подстроку {0}, {1} и т. д. m1 представляет первую совпадающую группу, то есть часть, заключенную в квадратные скобки в регулярном выражении, которая является 0 для первого совпадения. position - это начальный индекс в строке, в которой была найдена соответствующая группа - в данном случае не используется.

String#matchAll (см. Проект этапа 3 / Предложение от 7 декабря 2018 г.), упрощает доступ ко всем группам в объекте сопоставления (помните, что группа 0 - это полное совпадение, а другие группы соответствуют группам захвата в шаблоне):

With matchAll available, you can avoid the while loop and exec with /g... Instead, by using matchAll, you get back an iterator which you can use with the more convenient for...of, array spread, or Array.from() constructs

Этот метод дает результат, аналогичный Regex.Matches в C#, re.finditer в Python, preg_match_all в PHP.

См. Демонстрацию JS (протестировано в Google Chrome 73.0.3683.67 (официальная сборка), бета (64-разрядная версия)):

var myString = "key1:value1, key2-value2!!@key3=value3";
var matches = myString.matchAll(/(\w+)[:=-](\w+)/g);
console.info([...matches]); // All match with capturing group values

console.info([...matches]) показывает

Вы также можете получить значение соответствия или конкретные значения группы, используя

let matchData = "key1:value1, key2-value2!!@key3=value3".matchAll(/(\w+)[:=-](\w+)/g)
var matches = [...matchData]; // Note matchAll result is not re-iterable

console.info(Array.from(matches, m => m[0])); // All match (Group 0) values
// => [ "key1:value1", "key2-value2", "key3=value3" ]
console.info(Array.from(matches, m => m[1])); // All match (Group 1) values
// => [ "key1", "key2", "key3" ]

ПРИМЕЧАНИЕ: см. Подробности совместимость с браузером.

Идеальный пример для пар ключ-значение. Лаконичный и удобный для чтения, очень простой в использовании. Кроме того, лучшая обработка ошибок, спред будет возвращать пустой массив, а не null, поэтому больше не будет 'error, no property "length" of null'

Jarrod McGuire 29.03.2019 17:54

We can access the matched group in a regular expressions by using backslash followed by number of the matching group:

/([a-z])\1/

В коде \ 1 представлена ​​первая группа ([a-z])

Получить все вхождения группы

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

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

console.info(m);

Я такой же, как я, и хочу, чтобы регулярное выражение возвращало такой объект:

{
    match: '...',
    matchAtIndex: 0,
    capturedGroups: [ '...', '...' ]
}

затем отрежьте функцию снизу

/**
 * @param {string | number} input
 *          The input string to match
 * @param {regex | string}  expression
 *          Regular expression 
 * @param {string} flags
 *          Optional Flags
 * 
 * @returns {array}
 * [{
    match: '...',
    matchAtIndex: 0,
    capturedGroups: [ '...', '...' ]
  }]     
 */
function regexMatch(input, expression, flags = "g") {
  let regex = expression instanceof RegExp ? expression : new RegExp(expression, flags)
  let matches = input.matchAll(regex)
  matches = [...matches]
  return matches.map(item => {
    return {
      match: item[0],
      matchAtIndex: item.index,
      capturedGroups: item.length > 1 ? item.slice(1) : undefined
    }
  })
}

let input = "key1:value1, key2:value2 "
let regex = /(\w+):(\w+)/g

let matches = regexMatch(input, regex)

console.info(matches)

Однострочное решение:

const matches = (text,regex) => [...text.matchAll(regex)].map(([match])=>match)

Итак, вы можете использовать этот способ (необходимо использовать / g):

matches("something format_abc", /(?:^|\s)format_(.*?)(?:\s|$)/g)

результат:

[" format_abc"]

ПРОСТО ИСПОЛЬЗУЙТЕ RegExp. $ 1 ... $ n -я группа например:

1.Для соответствия 1-й группе RegExp. $ 1

  1. Для соответствия 2-й группе RegExp. $ 2

если вы используете 3 группы в regex likey (обратите внимание на использование после string.match (regex))

Регулярное выражение $ 1 Регулярное выражение $ 2 Регулярное выражение $ 3

 var str = "The rain in ${india} stays safe"; 
  var res = str.match(/\${(.*?)\}/ig);
  //i used only one group in above example so RegExp.$1
console.info(RegExp.$1)

//easiest way is use RegExp.$1 1st group in regex and 2nd grounp like
 //RegExp.$2 if exist use after match

var regex=/\${(.*?)\}/ig;
var str = "The rain in ${SPAIN} stays ${mainly} in the plain"; 
  var res = str.match(regex);
for (const match of res) {
  var res = match.match(regex);
  console.info(match);
  console.info(RegExp.$1)
 
}

Как сказано в @cms в ECMAScript (ECMA-262), вы можете использовать matchAll. Он возвращает итератор и, помещая его в [... ] (оператор распространения), преобразует его в массив. (Это регулярное выражение извлекает URL-адреса имен файлов)

let text = `<a href = "http://myhost.com/myfile_01.mp4">File1</a> <a href = "http://myhost.com/myfile_02.mp4">File2</a>`;

let fileUrls = [...text.matchAll(/href = "(http\://[^"]+\.\w{3})\"/g)].map(r => r[1]);

console.info(fileUrls);

Другие вопросы по теме