Javascript正则表达式中被动(非捕获)组的用途是什么?
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}/ 等等
(?:组)
换句话说,这两件事看起来是一样的:
"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)/
(非捕获组)。请注意,尾随的?
应用于整个组(bar)
(在这种情况下,它由一个简单的字符序列bar
组成)。如果您只是想检查输入是否与您的正则表达式匹配,那么无论您使用的是捕获组还是非捕获组,它们的行为都是相同的(除了非捕获组是相同的)/(\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:谢谢你的反馈,但我不认为那是纯粹的学究主义。一个人可以在多年内成功地编写正则表达式,但却完全忽略了非捕获组的存在,因此我认为它们与正则表达式本身或量词等其他东西不属于同一类。“我什么时候需要使用
+
”不会保证这个回答。我不是说这不是一个有效的观点,只是这不是最重要的