[英]Javascript RegExp non-capturing groups
我正在编写一组RegExps,以将CSS选择器转换为ID和类的数组。
例如,我希望'#foo#bar'返回['foo','bar']。
我一直在努力实现这一目标
"#foo#bar".match(/((?:#)[a-zA-Z0-9\-_]*)/g)
但当非捕获前缀?:忽略#字符时,它将返回['#foo','#bar']。
是否有比将每个返回的字符串切片更好的解决方案?
您可以在循环中使用.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)正在捕获。 内部组(#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]);
}
看到它在行动 。
我不确定是否可以使用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'
}
不幸的是,Javascript RegExp中没有后向断言,否则您可以这样做:
/(?<=#)[a-zA-Z0-9\-_]*/g
除了将其添加到某些新版本的Javascript中之外,我认为使用split
后处理是最好的选择。
您可以使用否定的超前断言:
"#foo#bar".match(/(?!#)[a-zA-Z0-9\-_]+/g); // ["foo", "bar"]
mVChr几年前提到的回溯断言已添加到ECMAScript 2018中 。 这将允许您执行以下操作:
'#foo#bar'.match(/(?<=#)[a-zA-Z0-9\\-_]*/g)
(返回["foo", "bar"]
)
(也可以使用负向后看:使用(?<!#)
匹配除#以外的任何字符,而不捕获它。)
MDN确实记录到“使用带全局/ g标志的match()时 , 捕获组将被忽略” ,并建议使用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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.