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

时间:2015-11-04 17:55:40

标签: regex delphi-xe5

我有一个与Regex匹配的简单模式:

{tag:value=text}

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

以下是一些样本:

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

第一行应该有"标记"在"标签"捕获组,"价值"在"值"捕获组和"文本"在文本捕获组中。另外两行不应该有任何"值"捕获组(或者它可能是空的)

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

{(?<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}

2 个答案:

答案 0 :(得分:4)

你的问题的根源来自使用.*太过宽松(并且当模式工作时可能会导致大量的回溯)。您可以使用适当的否定字符类替换所有这些.

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

demo

使用否定的字符类,您总是可以使用贪婪的量词,因为这是停止量词的允许字符集,如果下一个是:,则正则表达式引擎不必测试每个字符,=}

答案 1 :(得分:3)

这可以解决这个问题吗?它在?之后使用非贪婪修饰符.*。这使得它匹配尽可能少的字符,而不是尽可能多的字符。由于后面的字符是:=,因此它会在到达之前停止。

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

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

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

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

更新了网址:https://regex101.com/r/fD2eR6/2