Java 正则表达式捕获组索引
Posted
技术标签:
【中文标题】Java 正则表达式捕获组索引【英文标题】:Java regex capturing groups indexes 【发布时间】:2013-05-07 05:30:22 【问题描述】:我有以下行,
typeName="ABC:xxxxx;";
我需要获取单词ABC
,
我写了如下代码sn-p,
Pattern pattern4=Pattern.compile("(.*):");
matcher=pattern4.matcher(typeName);
String nameStr="";
if(matcher.find())
nameStr=matcher.group(1);
所以如果我输入group(0)
我得到ABC:
但如果我输入group(1)
它是ABC
,所以我想知道
0
和 1
是什么意思?如果有人能用很好的例子来解释我,那就更好了。
正则表达式模式中包含一个:
,那么为什么group(1)
结果会忽略它呢?第 1 组是否检测到括号内的所有单词?
那么,如果我多放两个括号,例如\\s*(\d*)(.*)
: 那么,会有两组吗? group(1)
将返回 (\d*)
部分,group(2)
将返回 (.*)
部分?
代码 sn-p 是为了消除我的困惑。这不是我正在处理的代码。上面给出的代码可以用String.split()
以更简单的方式完成。
【问题讨论】:
【参考方案1】:捕获和分组
捕获组 (pattern)
创建一个具有捕获 属性的组。
您可能经常看到(和使用)的一个相关的是(?:pattern)
,它创建了一个没有capturing 属性的group,因此命名为non-capturing组。
当您需要重复一系列模式时,通常使用组,例如(\.\w+)+
,或指定更改应在何处生效,例如^(0*1|1*0)$
(^
,然后是0*1
或1*0
,然后是$
)与^0*1|1*0$
(^0*1
或1*0$
)。
一个捕获组,除了分组,还会记录捕获组(pattern)
内的pattern匹配的文本。使用您的示例,(.*):
、.*
匹配 ABC
和 :
匹配 :
,并且由于 .*
在捕获组 (.*)
内,因此为捕获组 1 记录了文本 ABC
。
组号
整个模式定义为组号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开始,你可以定义一个named capturing group(?<name>pattern)
,你可以访问与Matcher.group(String name)
匹配的内容。正则表达式更长,但代码更有意义,因为它指示您尝试与正则表达式匹配或提取的内容。
组名用于反向引用模式中的\k<name>
和替换字符串中的$name
。
命名的捕获组仍然使用相同的编号方案进行编号,因此也可以通过Matcher.group(int group)
访问它们。
在内部,Java 的实现只是从名称映射到组号。因此,您不能为 2 个不同的捕获组使用相同的名称。
【讨论】:
哇!感谢@nhahtdh 用嵌套组顺序的工作原理解释非捕获组。在我最终阅读您的解释之前,我对组号的工作方式感到困惑。非常感谢!【参考方案2】:对于我们其他人
这里有一个简单明了的例子来说明它是如何工作的: ( 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
如您所见,我创建了五个组,每个组都用括号括起来。
我包括了 !* 和 *!在任一侧使其更清晰。请注意,这些字符都不在 RegEx 中,因此不会在结果中生成。 Group(0) 只为您提供整个匹配的字符串(我的所有搜索条件都在一行中)。第 1 组在第一个空格之前停止,因为空格字符未包含在搜索条件中。第 2 组和第 4 组只是空白,在这种情况下实际上是空格字符,但也可以是制表符或换行符等。第 3 组包括空格,因为我将它放在搜索条件中......等等。
希望这是有道理的。
【讨论】:
完美的例子,初学者容易理解。我怀疑这与python中的reg ex分组相同吗?否则有什么区别吗?我是 reg ex 的新手,这就是为什么我对两种语言都有点困惑。 这不是一个有效的 Java 正则表达式:反斜杠必须加倍。 @NicolasRaoul:双反斜杠是由于字符串文字中的转义语法造成的。实际的正则表达式语法(即,如果您将包含正则表达式的字符串打印到控制台)不需要双反斜杠。 @NicolasRaoul 如果您要使用合格的 IDE 将我的正则表达式字符串复制并粘贴到实际的 Java 代码中,IDE 会根据需要正确格式化转义斜杠。但是我的正则表达式在技术上和语法上都是正确的,它的主要目的是展示正则表达式代码和获得的结果之间的关联(使用一个非常具体的例子)......减轻一点......☺ 很有趣,同时也击中了靶心。伟大的工作@MichaelSims【参考方案3】:括号()
用于启用正则表达式短语的分组。
group(1)
包含括号 (.*)
之间的字符串,因此在这种情况下为 .*
而group(0)
包含整个匹配的字符串。
如果您有更多组(阅读(...)
),它将被放入具有下一个索引(2、3 等)的组中。
【讨论】:
那么,添加括号实际上是为了创建组,我说得对吗?以上是关于Java 正则表达式捕获组索引的主要内容,如果未能解决你的问题,请参考以下文章