JavaScript RegExp без захвата групп

Я пишу набор регулярных выражений для перевода селектора CSS в массивы идентификаторов и классов.

например, я хотел бы, чтобы '#foo#bar' вернул ['foo','bar'].

Я пытался достичь этого с

"#foo#bar".match(/((?:#)[a-zA-Z0-9-_]*)/g)

но он возвращает ['#foo', '#bar'], когда префикс без захвата ?: следует игнорировать символ#.

есть ли лучшее решение, чем нарезка каждой из возвращаемых строк?

6 ответов


вы могли бы использовать .replace() или .exec() в цикле для построения массива.

С .replace():

var arr = [];
"#foo#bar".replace(/#([a-zA-Z0-9\-_]*)/g, function(s, g1) {
                                               arr.push(g1);
                                          });

С .exec():

var arr = [],
    s = "#foo#bar",
    re = /#([a-zA-Z0-9\-_]*)/g,
    item;

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

соответствует #foo и #bar, потому что внешний группа (#1) захватывает. The внутренний group (#2) нет, но это, вероятно, не то, что вы проверяете.

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

с глобальным режимом сопоставления результат не может быть только в одной строке, потому что match ведет себя по-разному. Использование только регулярного выражения (т. е. без строки операции) вам нужно будет сделать это следующим образом:

var re = /(?:#)([a-zA-Z0-9\-_]*)/g;
var matches = [], match;
while (match = re.exec("#foo#bar")) {
    matches.push(match[1]);
}

посмотреть его в действии.


Я не уверен, что вы можете сделать это с помощью match (), но вы можете сделать это с помощью метода exec () RegExp:

var pattern = new RegExp('#([a-zA-Z0-9\-_]+)', 'g');
var matches, ids = [];

while (matches = pattern.exec('#foo#bar')) {
    ids.push( matches[1] ); // -> 'foo' and then 'bar'
}

вы можете использовать отрицательное утверждение lookahead:

"#foo#bar".match(/(?!#)[a-zA-Z0-9\-_]+/g);  // ["foo", "bar"]

к сожалению, в JavaScript RegExp нет утверждения lookbehind, иначе вы могли бы сделать это:

/(?<=#)[a-zA-Z0-9\-_]*/g

кроме того, что он добавляется в какую-то новую версию Javascript, я думаю, используя split обработка сообщений - ваш лучший выбор.


утверждение lookbehind, упомянутое несколько лет назад mVChr, является добавлено в ECMAScript 2018. Это позволит вам сделать следующее:

'#foo#bar'.match(/(?<=#)[a-zA-Z0-9\-_]*/g) (возвращает ["foo", "bar"])

(отрицательный lookbehind также возможен: используйте (?<!#) чтобы соответствовать любому символу, кроме#, без его захвата.)