Javascript RegEx非捕获组

时间:2012-06-02 18:16:35

标签: javascript regex capturing-group regex-group

我正在编写一组RegExps来将CSS选择器转换为id和类的数组。

例如,我希望'#foo#bar'返回['foo','bar']。

我一直试图用

来实现这一目标
"#foo#bar".match(/((?:#)[a-zA-Z0-9\-_]*)/g)

但是当非捕获前缀?:应该忽略#字符时,它返回['#foo','#bar']。

有没有比切换每个返回字符串更好的解决方案?

7 个答案:

答案 0 :(得分:12)

您可以在循环中使用.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]);

答案 1 :(得分:4)

它与#foo#bar匹配,因为外部组(#1)正在捕获。 内部组(#2)不是,但那可能不是你要检查的内容。

如果您没有使用全局匹配模式,则立即修复将使用(/(?:#)([a-zA-Z0-9\-_]*)/

使用全局匹配模式时,结果不能仅在一行中生成,因为match的行为不同。只使用正则表达式(即没有字符串操作),你需要这样做:

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

See it in action

答案 2 :(得分:2)

我不确定你是否可以使用match()来做到这一点,但你可以使用RegExp的exec()方法来做到这一点:

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'
}

答案 3 :(得分:1)

不幸的是,在Javascript RegExp中没有lookbehind断言,否则你可以这样做:

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

除了将其添加到某个新版本的Javascript之外,我认为使用split后期处理是最好的选择。

答案 4 :(得分:1)

您可以使用否定先行断言:

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

答案 5 :(得分:1)

几年前mVChr提到的后视断言是added in ECMAScript 2018。这将允许您这样做:

'#foo#bar'.match(/(?<=#)[a-zA-Z0-9\-_]*/g)(返回["foo", "bar"]

(也可以使用负面的后视:使用(?<!#)匹配除#之外的任何字符,而不捕获它。)

答案 6 :(得分:0)

MDN确实记录了"Capture groups are ignored when using match() with the global /g flag",并建议使用matchAll()matchAll() isn't available on Edge or Safari iOS, and you still need to skip the complete match (including the#`)。

一种更简单的解决方案是,如果您知道前导前缀的长度,则将其切掉-在这里,#为1。

const results = ('#foo#bar'.match(/#\w+/g) || []).map(s => s.slice(1));
console.log(results);

如果没有匹配项,则必须使用[] || ...部分,否则match返回null,而null.map将不起作用。

const results = ('nothing matches'.match(/#\w+/g) || []).map(s => s.slice(1));
console.log(results);