在正则表达式的可选部分中捕获的组

Posted

技术标签:

【中文标题】在正则表达式的可选部分中捕获的组【英文标题】:Captured group in optional part of a regular expression 【发布时间】:2015-04-05 01:08:12 【问题描述】:

我想在字符串的可选部分捕获一个组。

例如:

在字符串“firstName:Bill-lastName:Gates”中,我想捕获2组:

    比尔 盖茨

我使用这个正则表达式:

firstName:(.*)-lastName:(.*)

但是当lastName-part是可选的时候,我还是想抓到第一个 组(名字)。

我使用了这个正则表达式,使 lastName 部分成为可选的(在非捕获组中):

firstName:(.*)(?:-lastName:(.*))?

使用这个更新的正则表达式,生成的组是:

当 lastName 部分不存在时,例如 "firstName:Bill" 捕获的组是:

    比尔 /空字符串/

这是正确的

当 firstName 和 lastName 部分存在时:"firstName:Bill-lastName:Gates"组不正确

    比尔姓氏:盖茨 /空/

我认为这与第一个捕获组的贪婪有关,但是当 lastName-part 是可选的时,如何调整这个正则表达式以使正则表达式工作?

【问题讨论】:

【参考方案1】:

你是对的,这是关于贪婪。查找第一个匹配组的分隔符。因此,如果您的名字“从不”包含破折号,则仅将破折号以外的所有内容与第一个匹配组匹配。

firstName:([^-]*)(?:-lastName:(.*))?

firstName:([^-]*)(?:-lastName:(.*))?

Debuggex Demo

如果找不到这样的分隔符,则需要采取不同的方法。即使您尝试使第一个模式“惰性”,Regex 引擎总是更喜欢 更大的 匹配而不是匹配额外的可选匹配。

这是因为惰性匹配组将匹配满足表达式的第一个字符串(!重要的措辞!)

可能有一个带有外观的选项,但您也可以使用 or 语句而不提供可选匹配项:

firstName:(.*)-lastName:(.*)|firstName:(.*)

这样,正则表达式引擎将匹配或匹配,但更喜欢具有 2 个匹配项的模式,因为它首先列出。只有当这不适用时,它才会尝试单一匹配。

【讨论】:

谢谢,效果很好! +1 用于 Debuggex 可视化工具和 or 语句解释。 你为什么重复同一行两次?【参考方案2】:

即使您已经接受了@dognose 的回答,我向您保证,名字中有破折号(您不想惹恼 Jean-Claude van Damme)。我建议你这样做:

    firstName:((?:(?!-lastName:).)*)(?:-lastName:(.*))?

Debuggex Demo

您可以从可视化中看到(?:(?!-lastName:).) 表示“如果当前位置后面没有'-lastName:',则捕获另一个字符” p>

【讨论】:

以上是关于在正则表达式的可选部分中捕获的组的主要内容,如果未能解决你的问题,请参考以下文章

c# 正则表达式捕获

正则表达式中 ?,+,*,{}的运用

匹配正则表达式中的可选斜杠

正则表达式进阶

如何使用 python 正则表达式替换使用捕获的组? [复制]

java正则表达式匹配IP地址和端口号作为捕获的组