首页 文章

Javascript RegExp非捕获组

提问于
浏览
10

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

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

我一直在努力实现这一目标

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

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

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

6 回答

  • 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]);
    
  • 2

    它与 #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 .

  • 0

    我不确定你是否可以使用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'
    }
    
  • 1

    您可以使用负前瞻断言:

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

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

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

    除了它被添加到一些新版本的Javascript,我认为使用 split 后期处理是你最好的选择 .

  • 2

    几年前由mVChr提到的观察性断言是added in ECMAScript 2018 . 这将允许您这样做:

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

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

相关问题