简体   繁体   English

Javascript RegExp非捕获组

[英]Javascript RegExp non-capturing groups

I am writing a set of RegExps to translate a CSS selector into arrays of ids and classes. 我正在编写一组RegExps,以将CSS选择器转换为ID和类的数组。

For example, I would like '#foo#bar' to return ['foo', 'bar']. 例如,我希望'#foo#bar'返回['foo','bar']。

I have been trying to achieve this with 我一直在努力实现这一目标

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

but it returns ['#foo', '#bar'], when the non-capturing prefix ?: should ignore the # character. 但当非捕获前缀?:忽略#字符时,它将返回['#foo','#bar']。

Is there a better solution than slicing each one of the returned strings? 是否有比将每个返回的字符串切片更好的解决方案?

You could use .replace() or .exec() in a loop to build an Array. 您可以在循环中使用.replace().exec()来构建数组。

With .replace() : 使用.replace()

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

With .exec() : 使用.exec()

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

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

It matches #foo and #bar because the outer group (#1) is capturing. 它与#foo#bar匹配,因为外部组(#1)正在捕获。 The inner group (#2) is not, but that' probably not what you are checking. 内部组(#2)不是,但是那可能不是您要检查的组。

If you were not using global matching mode, an immediate fix would be to use (/(?:#)([a-zA-Z0-9\\-_]*)/ instead. 如果您没有使用全局匹配模式,则立即解决方法是改用(/(?:#)([a-zA-Z0-9\\-_]*)/

With global matching mode the result cannot be had in just one line because match behaves differently. 在全局匹配模式下,由于match行为不同,因此结果不能仅一行显示。 Using regular expression only (ie no string operations) you would need to do it this way: 仅使用正则表达式(即不使用字符串操作),您需要这样做:

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

See it in action . 看到它在行动

I'm not sure if you can do that using match(), but you can do it by using the RegExp's exec() method: 我不确定是否可以使用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'
}

Unfortunately there is no lookbehind assertion in Javascript RegExp, otherwise you could do this: 不幸的是,Javascript RegExp中没有后向断言,否则您可以这样做:

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

Other than it being added to some new version of Javascript, I think using the split post processing is your best bet. 除了将其添加到某些新版本的Javascript中之外,我认为使用split后处理是最好的选择。

您可以使用否定的超前断言:

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

The lookbehind assertion mentioned some years ago by mVChr is added in ECMAScript 2018 . mVChr几年前提到的回溯断言已添加到ECMAScript 2018中 This will allow you to do this: 这将允许您执行以下操作:

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

(A negative lookbehind is also possible: use (?<!#) to match any character except for #, without capturing it.) (也可以使用负向后看:使用(?<!#)匹配除#以外的任何字符,而不捕获它。)

MDN does document that "Capture groups are ignored when using match() with the global /g flag" , and recommends using matchAll() . MDN确实记录到“使用带全局/ g标志的match()时捕获组将被忽略” ,并建议使用matchAll() matchAll() isn't available on Edge or Safari iOS, and you still need to skip the complete match (including the #`). matchAll() isn't available on Edge or Safari iOS, and you still need to skip the complete match (including the #`)。

A simpler solution is to slice off the leading prefix, if you know its length - here, 1 for # . 一个更简单的解决方案是,如果您知道前导前缀的长度,则将其切掉-在这里, # 1。

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

The [] || ... [] || ... [] || ... part is necessary in case there was no match, otherwise match returns null, and null.map won't work. [] || ...部分是必需的,以防不存在匹配项,否则match返回null,并且null.map将不起作用。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM