正则表达式 - 捕获组的混淆

3
我正在阅读一份关于正则表达式的Oracle教程,现在看到了捕获组这个主题。尽管参考资料很好,但除了括号表示一个组这一点之外,我仍然很难理解这个主题。以下是我的疑惑:
  1. 计算表达式中组的意义是什么?
  2. 什么是非捕获组?
带有示例的详细说明将会更好。
3个回答

3
  1. 通常,在使用正则表达式时,我们不会对组进行计数,而只是知道每个组的编号。例如,([abc])([def](\d+)) 有三个组,所以我知道可以用 \1\2\3 来引用它们。请注意,组 3 在组 2 的内部。它们按从左到右开始的位置编号。
  2. 在使用正则表达式搜索字符串中的内容时(与匹配整个字符串不同),组 0 将仅提供匹配的字符串,而不包括其前面或后面的内容。想象一下,你的整个正则表达式周围有一对括号。它不是总数的一部分,因为它实际上不被视为一个组。
  3. 组还可以用于除捕获之外的其他目的。例如,(foo|bar) 将匹配 "foo""bar"。如果你不关心组的内容,可以将其设置为非捕获组(例如:(?:foo|bar)(具体取决于方言)),以便不使用分配给组的数字。但你也可以不这样做,有时候这样做很方便。
  4. 假设我想要查找以相同字母开头和结尾的单词:\b([a-z])[a-z]*\1\b 然后 \1 将与第一个组捕获的内容相同。当然,它可以用于更强大的操作,但我想你会明白的。

(想出相关的例子肯定是最难的部分。)

编辑: 我回答的问题是:

  1. 计算表达式中组的数量的重要性是什么?
  2. 有一个特殊的组,称为组-0,表示整个表达式。它不会被 groupCount() 方法报告。为什么?
  3. 我不理解非捕获组是什么?
  4. 为什么我们需要反向引用?反向引用的意义是什么?

1
@benz 假设我有一个正则表达式,其中包含多个组,我想要使用它们的内容。我将它们设置为捕获组,以便可以在正则表达式本身中使用它们的内容(使用反向引用\1等),或者在使用的任何正则表达式库中使用它们(例如match.GetGroup(1))。然后假设我有一个地方想要匹配三个单词中的一个,但我不关心它是哪一个:...(?:one|two|three)... 我将其设置为非捕获组,以免为其分配编号;只有我感兴趣的内容所在的组才会有编号。 - Biffen

2
假设你有一个字符串abcabc,你想要确定这个字符串的前半部分是否与后半部分匹配。你可以使用一个正则表达式来实现,通过使用捕获组和反向引用。下面是我会使用的正则表达式:
(.+)\1

这个方法的工作原理是.+匹配任何字符序列。由于它在括号中,它被分组捕获\1是对第一个捕获组的向后引用,因此它等效于由捕获组捕获的文本。经过一些回溯,捕获组匹配字符串的第一部分,即abc。现在,向后引用\1等同于abc,因此它匹配字符串的第二半部分。整个字符串现在已匹配,因此确认字符串的前半部分与后半部分匹配。
另一种使用向后引用的方法是替换。如果您想用[...]替换所有{...},如果花括号内的文本只包含数字,则可以使用捕获组和向后引用轻松实现,使用正则表达式:
{(\d+)}

将其替换为 [\1] 。

正则表达式在字符串 abc {123} 456 中匹配 {123} ,并在第一个捕获组中捕获 123 。回溯引用 \1 现在等同于 123 ,因此使用 [\1] 替换 abc {(\d +)} 会导致 abc [123] 456 。


非捕获组存在的原因是因为组通常具有不仅限于捕获的更多用途。正则表达式(xyz)+ 匹配完全由重复的组 xyz 组成的字符串,例如 xyzxyzxyz 。需要组,因为 xyz + 仅匹配 xy ,然后是重复的 z ,即 xyzzzzz 。使用捕获组的问题在于它们与非捕获组相比略微低效,并且它们占据索引。如果您有一个包含许多组的复杂正则表达式,但只需要在中间某个位置引用单个正则表达式,则最好只引用 \1 ,而不是尝试计算到您需要的那个组。

希望这可以帮助你!


谢谢你,Ryan。这些例子非常有帮助。非常感谢。 - benz

1
  1. 暂时想不到一个合适的例子,但我假设有人可能需要知道正则表达式中子匹配的数量。
  2. 第 0 组始终是整个基本匹配。我假设 groupCount() 只是让你知道在表达式中指定了多少个捕获组。
  3. 非捕获组 (?:) 用于不捕获组。例如,如果您需要测试字符串是否包含多个单词之一并且不想在新组中捕获该单词:(?:hello|hi there) world !== hello|hi there world。第一个匹配“hello world”或“hi there world”,但第二个匹配“hello”或“hi there world”。
  4. 它们可以用作各种强大原因的一部分,例如测试数字是质数还是合数。 :) 或者您可以简单地测试以确保搜索参数不重复,即 ^(\d)(?!.*\1)\d+$ 将确保字符串中的第一个数字是唯一的。

虽然有趣的,但是测试质数应该使用整数操作,而不是正则表达式。这更多是一种可能性,而不是一个好的解决方案。 - nhahtdh

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