【问题标题】:Why does this non-capturing group capture?为什么这个非捕获组捕获?
【发布时间】:2013-01-25 02:37:13
【问题描述】:

应用这个正则表达式模式:

/(?:(^| |\>|\+))+([a-z\-\_]+)/gi

到这个字符串:

body.test ol+li ol > li #foobar p>span a[href=*]

我得到这些匹配,逗号分隔:

body, ol,+li, ol, > li, p,>span, a

为什么有些匹配有前导空格>+ 符号?我希望我的正则表达式 (?:(^| |\>|\+)) 的这一部分与这些标志匹配,但不捕获它们。

编辑:我正在尝试匹配有助于 css 选择器的 css 特异性的 html 标记和 css 选择器。因此,我想单独匹配每个lispan 等等,而不需要+>

【问题讨论】:

    标签: javascript regex css-selectors pattern-matching


    【解决方案1】:

    捕获不等于匹配。由于您在模式中指定了组合子,因此无论它们是被捕获还是未被捕获,它们都会被匹配器拾取。

    要捕获,您需要在字符串上exec() 您的正则表达式并循环遍历结果,其中包含您的捕获组。我还清理了您的模式并对其进行了修改,因此它不会不必要地捕获并识别the general sibling combinator ~

    var sel = "body.test ol+li ol > li #foobar p>span a[href=*]";
    var re = /(?:^| |>|\+|~)+([a-z_-]+)/gi;
    var matches = [], m;
    
    while (m = re.exec(sel)) {
        matches.push(m[1]);
    }
    

    然后您将获得预期的匹配:

    body, ol, li, ol, li, p, span, a
    

    【讨论】:

    • 完美的解释和答案。在 while 循环中调试 m 的内容有助于我了解发生了什么。我在a small javascript module that calculates css specifity使用它。
    • @kontur:你可能想要重命名它——正确的拼写是“specificity”(即“specific”+“ity”):)
    【解决方案2】:

    (?:(^| |\>|\+)) 中的内括号正在创建一个捕获组。你也可以让它不被捕获,我认为你应该在外括号内有 + 量词:

    /(?:(?:^| |\>|\+)+)([a-z\-\_]+)/gi
    

    另外,您可以使用字符类来避免在两者之间出现pipes,并且您也不需要转义>+。但是请记住,不要在字符类的开头使用caret(^),否则会否定一切:

    /(?:[ >+^]+)([a-z_-]+)/gi
    

    您无需在字符类中转义 -_。只需在最后使用-,一切都很好。

    【讨论】:

    • 嗯,很奇怪,当我试图找出问题所在时,我在这个在线正则表达式测试器上试过:regex.larsolavtorvik.com,它似乎有问题 - 它仍然显示与 + 等匹配。在rubular.com 上尝试相同的建议有效。问题解决了,应该避免第一个正则表达式工具。也感谢您对角色类的建议!
    • (?:^|[ >+]) 这行得通,似乎类内的^ 表示否定,而不是行开头。
    • @kontur.. 不,当您在开头使用^ 时,它才表示否定。否则它只是^。无论如何,我已经更新了第一个正则表达式,你需要在那里使用嵌套的非捕获组,因为你使用的是量词。
    • 这里有很棒的见解,谢谢!这里的正则表达式处理会有所不同吗?在线 javascript 正则表达式工具以及我的 firefox 似乎仍然匹配那些 + 标志,但 ruby​​ 正则表达式在线工具与它们不匹配。或者我在这里错过了什么?此外,在regex.larsolavtorvik.com 使用正则表达式(?:[ >+^]+)([a-z_-]+) 与起始body 标记不匹配,这就是为什么我认为^ 需要在组之外。
    • regex.larsolavtorvik.com 在 javascript 选项卡上,以及 Firefox。
    【解决方案3】:

    这里有捕获组:(^| |\>|\+)

    【讨论】:

      【解决方案4】:

      您有两个捕获组,(^| |\>|\+)([a-z\-\_]+) - 第一个直接位于非捕获组内。只需将其删除:

      /(?:^| |>|\+)+([a-z_-]+)/gi
      

      关于如何在重复(全局)匹配时获取捕获的组,请参阅JavaScript regular expressions and sub-matches。顺便说一句,您也可以尝试使用.split(/[ >+]+/).match(/[^ >+]+/g)

      【讨论】:

      • @RohitJain 已经指出了这一点。不知何故,尽管我仍然得到包含 +> 标志以及空格的匹配项。
      • 整个匹配当然包括所有字符。第一个(也是唯一的)捕获组不会。你如何应用正则表达式?
      • "body, ol,+li, ol, > li, p,>span, a".match(/(?:(^| |\>|\+))+([a-z\-\_]+)/gi);
      • @kontur:这是匹配,而不是捕获。无论您是否正在捕获它,匹配总是会选择一个子模式。
      • @BoltClock 是的,我似乎错过了这种细微的差别——@RohitJain 在聊天中向我解释了这一点。 "Lorem ipsum dol solor".match(/(?: )/gi)匹配三个空格似乎仍然很奇怪。真的有点莫名其妙。我如何访问 captured 而不是 javascript 中的 matched 组?
      猜你喜欢
      • 2019-03-08
      • 1970-01-01
      • 2019-12-31
      • 1970-01-01
      • 2014-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-21
      相关资源
      最近更新 更多