正则表达式中的捕获组

34

我正在探索正则表达式中的捕获组,但是我很困惑它缺乏文档说明。例如,有人可以告诉我两个正则表达式之间的区别吗:

/(?:madhur)?/

并且

/(madhur)?/

我认为,第二个问题中的 ? 表示在字符串中与 madhur 匹配零次或一次。

第一个问题与第二个问题有何不同之处?

3个回答

35

第一个示例不会存储捕获组,例如 $1 将为空。前缀 ?: 使其成为非捕获组。通常这样做是为了提高性能并减少反向引用的混乱。

在第二个示例中,捕获组中的字符将存储在反向引用 $1 中。

更多阅读资料


为什么要使用非捕获分组?在这种情况下,括号不是多余的吗?换句话说,/(?:madhur)?/和/madhur?/之间有什么不同? - Didier A.
3
目的是对整个文本应用条件。这两者并不相同。第一个中madhur是可选的,而第二个中只有r是可选的。 - Muhammad Umer
@alex...为什么在match或split中使用捕获组结果会产生不同的结果。例如:" , ".match(/(\s+)?,(\s+)?/)的结果是**[","," "," "],而" , ".match(/(\s+)?,(\s+)?/g)" , ".match(/[\s+]?,[\s+]?/) 的结果是[","]**。你能解释一下为什么吗? - Muhammad Umer
1
@MuhammadUmer 如果你有捕获组,添加 g 可以改变 match() 返回匹配的方式。 - alex
我知道,我刚学会...https://dev59.com/ynbZa4cB1Zd3GeqPFGKo - Muhammad Umer

20

这是最明显的例子:

"madhur".replace(/(madhur)?/, "$1 ahuja");   // returns "madhur ahuja"
"madhur".replace(/(?:madhur)?/, "$1 ahuja"); // returns "$1 ahuja"

回溯引用按顺序存储,第一个匹配可以使用$1进行回忆,第二个可以使用$2,以此类推。如果你捕获了一个匹配(即使用(...)而不是(?:...)),则可以使用这些引用,否则就没有什么特殊的作用。另一个例子是:

/(mad)hur/.exec("madhur");   // returns an array ["madhur", "mad"]
/(?:mad)hur/.exec("madhur"); // returns an array ["madhur"]

6

这不会对匹配产生任何影响。

它告诉正则表达式引擎:

  • 不要存储组的内容,以便由 replace() 方法使用(如 $1、$2 等)
  • 不要在 exec() 方法的返回数组中返回该组
  • 不要将其作为反向引用(\1、\2 等)计数

1
一个小问题:它会在某些情况下改变匹配。例如,在 /(foo)\1/ 中将匹配 "foofoo",但在 /(?:foo)\1/ 中不会。在第一个中,\1 被解释为反向引用,在第二个中被解释为八进制转义序列。 - Mike Samuel
为什么这两个表达式 " , ".match(/(\s+)?,(\s+)?/) 和 `" , ".match(/[\s+]?,[\s+]?/) 会输出不同的数组? - Muhammad Umer
一个使用“一个或多个空格或没有空格”的组,另一个则使用“一个空格或加号或没有任何字符”的字符类。 - AndreKR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接