Java正则表达式捕获组索引

123

我有以下这行代码:

typeName="ABC:xxxxx;";

我需要获取单词ABC

我写了以下的代码片段,

Pattern pattern4=Pattern.compile("(.*):");
matcher=pattern4.matcher(typeName);

String nameStr="";
if(matcher.find())
{
    nameStr=matcher.group(1);

}

所以如果我输入 group(0) 我会得到 ABC:,但如果我输入 group(1),那么它就是 ABC。因此我想知道:

  1. 01 是什么意思?如果有好的例子可以解释,那就更好了。

  2. 正则表达式模式中包含一个 :,为什么 group(1) 的结果不包括它?是因为组1检测到括号内的所有单词吗?

  3. 那么,如果我再加两个括号,例如:\\s*(\d*)(.*),那么会有两个组吗?group(1)将返回 (\d*) 部分,而group(2)将返回 (.*) 部分吗?

给出代码片段是为了澄清我的困惑。这不是我正在处理的代码。上面给出的代码可以使用 String.split() 更简单地完成。

3个回答

189

捕获和分组

捕获分组 (pattern) 创建了一个具有捕获属性的分组

你可能经常看到并使用的相关语法是(?:pattern),它创建了一个没有捕获属性的非捕获分组

当需要重复一系列模式时,通常会使用分组,例如(\.\w+)+,或者用于指定交替出现的位置,例如^(0*1|1*0)$(先是^,然后是0*11*0,最后是$),与^0*1|1*0$^0*11*0$)相对应。

除了进行分组之外,捕获分组还将记录匹配捕获分组内部模式的文本。以您的示例(.*):为例,.*匹配ABC:匹配:,由于.*在捕获分组(.*)内部,因此文本ABC被记录为捕获分组1。

分组编号

整个模式被定义为编号0的分组。

模式中的任何捕获分组都从1开始索引。这些索引是由捕获分组的左括号出现的顺序定义的。以下是下面模式中所有5个捕获分组的示例:

(group)(?:non-capturing-group)(g(?:ro|u)p( (nested)inside)(another)group)(?=assertion)
|     |                       |          | |      |      ||       |     |
1-----1                       |          | 4------4      |5-------5     |
                              |          3---------------3              |
                              2-----------------------------------------2

在模式中,你可以使用捕获组号码进行向后引用\n,在替换字符串中,你可以使用$n

在其他正则表达式语言(如PCRE、Perl)中,它们也可用于子程序调用。

你可以使用Matcher.group(int group)方法访问某些分组匹配的文本。可根据上述规则识别分组编号。

在某些正则表达式语言(如PCRE、Perl)中,有一种“分支重置”功能,允许您使用相同的号码来处理交替分支中不同的捕获组。

组名

从Java 7开始,你可以定义一个命名捕获组 (?<name>pattern),并且你可以使用Matcher.group(String name)方法访问匹配的内容。这个正则表达式比较长,但代码更有意义,因为它表示你正在尝试匹配或提取的内容。

组名可以在模式中使用向后引用\k<name>,在替换字符串中可以使用${name}

命名捕获组仍然使用相同的编号方案进行编号,因此它们也可以通过Matcher.group(int group)访问。

在内部,Java的实现只是将名称映射到组号码。因此,你不能为2个不同的捕获组使用相同的名称。


1
哇!谢谢 @nhahtdh 解释非捕获组和嵌套组顺序的问题。在读了你的解释之前,我对组号是如何工作一直感到困惑。非常感谢! - MMeah

107

对于我们其余的人

这里是一个简单明了的示例,说明它是如何工作的:

( G1 )( G2 )( G3 )( G4 )( G5 )
正则表达式:([a-zA-Z0-9]+)([\s]+)([a-zA-Z ]+)([\s]+)([0-9]+)

字符串:"!* UserName10 John Smith 01123 *!"

group(0): UserName10 John Smith 01123
group(1): UserName10
group(2):  
group(3): John Smith
group(4):  
group(5): 01123

你可以看到,我创建了五个被括号包含的组。

我在每一侧都加上了 !* 和 *! 以使其更清晰。请注意,这些字符都不在正则表达式中,因此不会出现在结果中。Group(0)仅仅给出整个匹配的字符串(所有搜索标准在单行中)。 Group 1在第一个空格之前停止,因为空格字符未包含在搜索标准中。组2和4只是表示空格,这里实际上是一个空格字符,但也可以是制表符或换行符等。Group 3包含空格,因为我将其放入了搜索标准...等等。

希望这样说得清楚。


2
完美的例子,易于初学者理解。我有一个疑问,这是否与Python中的正则表达式分组相同?还是有什么区别?我对正则表达式很新,所以在两种语言中都有点困惑。 - Mani
1
这不是一个有效的Java正则表达式:反斜杠必须加倍。 - Nicolas Raoul
1
@NicolasRaoul:双反斜杠是由于字符串文字中的转义语法。实际的正则表达式语法(即如果您将包含正则表达式的字符串打印到控制台)不需要双反斜杠。 - nhahtdh
@NicolasRaoul 如果您将我的正则表达式字符串复制并粘贴到使用能干的IDE的实际Java代码中,IDE将根据需要正确格式化转义斜杠。但是我的正则表达式在技术和语法上都是正确的,并且它的主要目的是演示正则表达式代码与所获得结果之间的关联(使用非常具体的示例)...放松一点...☺ - Michael Sims
同时有趣又精准。做得好,@MichaelSims。 - Asanka Siriwardena

47

圆括号()用于启用正则表达式短语的分组。

group(1)包含圆括号(.*)内的字符串,因此在此情况下是.*

group(0)包含整个匹配的字符串。

如果您有更多的分组(即(...)),它们将被放入下一个索引(2、3等)的组中。


2
那么,我理解正确,添加括号实际上是为了创建分组? - P basak

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