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 также возможен: используйте (?<!#)
чтобы соответствовать любому символу, кроме#, без его захвата.)