【问题标题】:Javascript RegExp non-capturing groupsJavascript RegExp 非捕获组
【发布时间】:2012-06-07 13:13:21
【问题描述】:

我正在编写一组正则表达式来将 CSS 选择器转换为 id 和类数组。

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

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

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

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

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

【问题讨论】:

  • 这是一个单行:str.replace(/[^#]+|(#[a-zA-Z0-9\-_]*)/g, '$1').split('#').slice(1)
  • 分割在 ie8 中不起作用
  • @webaba 为什么 ie8 甚至会与 2014 年 9 月的任何事情相关,除非它是一个特定的请求?

标签: javascript regex capturing-group regex-group


【解决方案1】:

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);

【讨论】:

    【解决方案2】:

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

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

    (也可以进行否定的向后查找:使用(?<!#) 匹配除# 之外的任何字符,而不捕获它。)

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 它确实返回 ['foo', 'bar'],但不会搜索 #,所以 "#foo#bar.foobar".match(/(?!#)[a -zA-Z0-9\-_]+/g);将返回 ['foo', 'bar', 'foobar']
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        它匹配 #foo#bar 因为 outer 组 (#1) 正在捕获。 inner 组 (#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.

        【讨论】:

        • 根本不需要对哈希键进行分组(然后排除它)。
        【解决方案6】:

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

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

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-10-13
            • 2021-06-24
            相关资源
            最近更新 更多