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

Optional capture group in regex

我有一个与正则表达式匹配的简单模式:

{tag:value=text}

tagvaluetext 是我要捕获的部分。诀窍是 value 是可选的(就像之前的文字“:”一样)

这里有一些示例:

{tag:value=text}
{tag=text}
{tag:=text}

第一行应该在 "tag" 捕获组中包含 "tag",在 "value" 捕获组中包含 "value",在文本捕获组中包含 "text" .另外两行不应该有任何 "value" 捕获组(或者它可以是空的)

我尝试了以下正则表达式的变体:

{(?<tag>.*):(?<value>.*)?=(?<text>.*)}

这适用于示例 1 和 3,但不适用于第二个。

给定文本中可以有任意数量的匹配项,我想抓取所有匹配项。

编辑: 这是我尝试匹配的一些数据样本:

Progress: {progress:p1=10%}
Planned duration: {time=10m}
Actors output: {actor:actor1=<nothing to say>}, {actor:actor2=<nothing to say>}
Scene comments: {display=This is a sample scene}

这样做有用吗?它在 .* 之后使用了一个非贪婪修饰符 ?。这导致它匹配尽可能少的字符,而不是尽可能多的字符。由于后面的字符是 :=,它会在到达它们之前停止。

{(.*?)(?::(.*?))?=(.*?)}

https://regex101.com/r/fD2eR6/1

编辑:如下所述,您正在寻找命名捕获。

{(?<tag>.*?)(?::(?<val>.*?))?=(?<text>.*?)}

已更新 URL:https://regex101.com/r/fD2eR6/2

问题的根源在于对 .* 的使用过于宽松(当模式有效时,这可能会导致大量回溯)。您可以将所有这些 . 替换为适当的否定字符 class:

{(?<tag>[^:=]*)(?::(?<value>[^=]*))?=(?<text>[^}]*)}

demo

对于取反字符 class,您始终可以使用贪婪量词,因为这是一组允许的字符来停止量词,并且如果下一个字符是,则正则表达式引擎不必测试每个字符一个 :、一个 = 或一个 }.