Javascript正则表达式中被动(非捕获)组的用途是什么?

Javascript正则表达式中被动(非捕获)组的用途是什么?,javascript,regex,Javascript,Regex,Javascript正则表达式中被动组的用途是什么 被动组前面有一个问号冒号:(?:组) 换句话说,这两件事看起来是一样的: "hello world".match(/hello (?:world)/) "hello world".match(/hello world/) 在什么情况下需要非捕获组?为什么?当您要对组应用修改器时 /hello (?:world)?/ /hello (?:world)*/ /hello (?:world)+/ /hello (?:world){3,6}/ 等等

Javascript正则表达式中被动组的用途是什么

被动组前面有一个问号冒号:
(?:组)

换句话说,这两件事看起来是一样的:

"hello world".match(/hello (?:world)/)
"hello world".match(/hello world/)

在什么情况下需要非捕获组?为什么?

当您要对组应用修改器时

/hello (?:world)?/
/hello (?:world)*/
/hello (?:world)+/
/hello (?:world){3,6}/

等等。

非捕获组与“正常”(捕获)组只有一个区别:它们不需要正则表达式引擎来记住匹配的内容

用例是,有时您必须(或应该)使用组,不是因为您对它捕获的内容感兴趣,而是出于语法原因。在这些情况下,使用非捕获组而不是“标准”捕获组是有意义的,因为它的资源密集度较低——但如果您不关心这一点,捕获组的行为方式将完全相同

您的特定示例不适合使用非捕获组,因为这两个表达式完全相同。更好的例子可能是:

input.match(/hello (?:world|there)/)

当您需要一个条件时使用它们,而不关心是哪个选项导致匹配

非捕获组可以简化匹配复杂表达式的结果。在这里,组1始终是发言者的名字。如果没有非捕获组,说话人的姓名可能会出现在组1或组2中

/hello(?:world | foobar)?said(+)/

捕获组的两个用例 正则表达式中的捕获组实际上有两个不同的目标(正如名称“捕获组”本身所示):

  • 分组-如果您需要将一个组视为一个单独的实体,以便将某些内容应用于整个组

    最简单的例子可能是包含一个可选的字符序列,例如,在正则表达式中,“foo”可选地后跟“bar:
    /foo(bar)/
    (捕获组)或
    /foo(?:bar)/
    (非捕获组)。请注意,尾随的
    应用于整个组
    (bar)
    (在这种情况下,它由一个简单的字符序列
    bar
    组成)。如果您只是想检查输入是否与您的正则表达式匹配,那么无论您使用的是捕获组还是非捕获组,它们的行为都是相同的(除了非捕获组是相同的)

  • 捕获-如果需要提取输入的一部分

    例如,您希望从输入中获取兔子的数量,如“农场包含8头牛和89只兔子”(我知道英语不是很好)。正则表达式可以是
    /(\d+)\s*rabbits\b/
    。成功匹配后,您可以获得捕获组(或任何其他编程语言)匹配的值

    在本例中,您只有一个捕获组,因此可以通过其索引
    0
    (有关详细信息,请参阅)

    现在想象一下,您希望确保“地方”被称为“农场”或“牧场”。如果不是这样,那么您不想提取兔子的数量(用正则表达式表示——您不希望正则表达式匹配)

    因此,您将正则表达式重写如下:
    /(farm | ranch)。*\b(\d+)\s*rabbts\b/
    。正则表达式可以自己工作,但是JavaScript被破坏了-现在有两个捕获组,您必须更改代码以获取第二个捕获组中兔子数量的内容(即,将索引从0更改为1)。第一个组现在包含字符串“farm”或“ranch”,这是您不打算提取的

    一个未捕获的小组前来营救:
    /(?:farm | ranch)。*\b(\d+)\s*兔子/b/
    。它仍然匹配“farm”或“ranch”,但不捕获它,因此不会移动后续捕获组的索引。您的JavaScript代码在不改变的情况下运行良好


  • 这个例子可能过于简单,但是考虑到你有一个非常复杂的正则表达式,有很多组,你只想捕获其中的几个。非捕获组真的很有用-你不必计算所有的组(只捕获一个)

    此外,非捕获组用于文档目的:对于阅读您代码的人来说,非捕获组表示您对提取内容不感兴趣,您只想确保它匹配


    关于分离关注点的几句话 捕获组是打破的一个典型例子。这个语法结构有两个不同的用途。随着问题的日益明显,引入了一个额外的构造(
    ?:
    )来禁用这两个功能之一

    这只是一个设计错误。也许是因为缺少“自由特殊角色”的缘故。。。但这仍然是一个糟糕的设计


    Regex是一个非常古老、强大且广泛使用的概念。由于向后兼容性的原因,现在不太可能修复此缺陷。这只是一个教训,说明分离关注点是多么重要

    除了上面的答案之外,如果您使用的是
    String.prototype.split()
    并且您使用的是捕获组,那么输出数组将包含捕获的结果()。如果您使用的是未捕获的组,则不会发生这种情况

    var myString = 'Hello 1 word. Sentence number 2.';
    var splits = myString.split(/(\d)/);
    
    console.log(splits);
    
    产出:

    ["Hello ", "1", " word. Sentence number ", "2", "."]
    
    而将
    /(\d)/
    替换为
    /(?:\d)/
    会导致:

    ["Hello ", " word. Sentence number ", "."]
    

    从技术上讲,您根本不需要regexp,就像任何抽象层或“代码”重用方法一样。我不确定学究主义是不是一种有用的领导方式。@millimoose:谢谢你的反馈,但我不认为那是纯粹的学究主义。一个人可以在多年内成功地编写正则表达式,但却完全忽略了非捕获组的存在,因此我认为它们与正则表达式本身或量词等其他东西不属于同一类。“我什么时候需要使用
    +
    ”不会保证这个回答。我不是说这不是一个有效的观点,只是这不是最重要的