Лучший способ хранения групп захвата JS Regex в массиве?

Именно то, что спрашивает название. Я приведу несколько примеров, объясняя свой вопрос.

Тестовая строка:

var test = "#foo# #foo# bar #foo#";

Скажем, я хочу извлечь весь текст между # (все foo, но не bar).

var matches = test.match(/#(.*?)#/g);

Используя .match, как указано выше, он сохранит все совпадения, но он просто выбросит группы захвата, которые, как кажется.

var matches2 = /#(.*?)#/g.exec(test);

Метод .exec, по-видимому, возвращает только строку с результатом первого результата в позиции 0 массива и мою единственную группу захвата этого совпадения в позиции 1.

Я исчерпал SO, Google и MDN, ища ответ безрезультатно.

Итак, мой вопрос заключается в том, есть ли лучший способ сохранить только согласованные группы захвата, чем прокручивать его с помощью .exec и вызывать array.push для хранения захваченных групп?

Мой ожидаемый массив для теста выше должен быть:

 [0] => (string) foo
 [1] => (string) foo
 [2] => (string) foo

Pure JS и ответы jQuery принимаются, дополнительные файлы cookie, если вы отправляете JSFiddle с помощью console.log. =]

Ответы

Ответ 1

Вы можете использовать .exec тоже, как показано ниже, для построения массива

var arr = [],
    s = "#foo# #bar# #test#",
    re = /#(.*?)#/g,
    item;

while (item = re.exec(s))
    arr.push(item[1]);

alert(arr.join(' '));​

Рабочая скрипта

Найдено здесь

Ну, у него все еще есть цикл, если вам не нужен цикл, я думаю, вам нужно пойти с .replace(). В этом случае код будет выглядеть как

var arr = [];
var str = "#foo# #bar# #test#"
str.replace(/#(.*?)#/g, function(s, match) {
                           arr.push(match);
                        });

Проверьте эти строки из MDN DOC, в котором объясняется ваш запрос о том, как exec обновляет свойство lastIndex, я думаю,

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

Когда вы это сделаете, поиск начинается с подстроки str, указанной в свойство lastIndex регулярного выражения (тест также будет продвигаться вперед свойство lastIndex).

Ответ 2

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

var matches = [];

var test = "#foo# #foo# bar #foo#";

test.replace(/#(.*?)#/g, function (string, match) {
    matches.push(match);
});

alert(JSON.stringify(matches));

Ответ 3

data.replace(/.*?#(.*?#)/g, '$1').split(/#/)
Нет циклов, нет функций.

Ответ 4

Другая мысль, хотя exec эффективна.

var s= "#foo# #foo# bar #foo#";
s= s.match(/#([^#])*#/g).join('#').replace(/^#+|#+$/g, '').split(/#+/);

Ответ 5

Если кто-то приходит с аналогичной потребностью в моей работе, мне нужна соответствующая функция для обработчика конфигурации URL-адреса Django, который может передавать "аргументы" пути к контроллеру. Я придумал это. Естественно, это не сработает, если совпадение "$", но оно не сломается "на $1.00". Это немного более явным, чем необходимо. Вы могли бы просто вернуть matchedGroups из инструкции else и не беспокоиться о тесте for loop, но;; в середине объявления цикла часто уродуют людей.

var url = 'http://www.somesite.com/calendar/2014/june/6/';
var calendarMatch = /^http\:\/\/[^\/]*\/calendar\/(\d*)\/(\w*)\/(\d{1,2})\/$/;

function getMatches(str, matcher){
    var matchedGroups = [];
    for(var i=1,groupFail=false;groupFail===false;i++){
        var group = str.replace(matcher,'$'+i);

        groupFailTester = new RegExp('^\\$'+i+'$');

        if(!groupFailTester.test(group) ){
            matchedGroups.push(group);
        }
        else {
            groupFail = true;
        }
    }
    return matchedGroups;
}

console.log( getMatches(url, calendarMatch) );