我有一个与Regex匹配的简单模式:
{tag:value=text}
tag
,value
和text
是我要捕获的部分。诀窍是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}
答案 0 :(得分:4)
你的问题的根源来自使用.*
太过宽松(并且当模式工作时可能会导致大量的回溯)。您可以使用适当的否定字符类替换所有这些.
:
{(?<tag>[^:=]*)(?::(?<value>[^=]*))?=(?<text>[^}]*)}
使用否定的字符类,您总是可以使用贪婪的量词,因为这是停止量词的允许字符集,如果下一个是:
,则正则表达式引擎不必测试每个字符,=
或}
。
答案 1 :(得分:3)
这可以解决这个问题吗?它在?
之后使用非贪婪修饰符.*
。这使得它匹配尽可能少的字符,而不是尽可能多的字符。由于后面的字符是:
或=
,因此它会在到达之前停止。
{(.*?)(?::(.*?))?=(.*?)}
https://regex101.com/r/fD2eR6/1
编辑:如下所述,您正在寻找命名捕获。
{(?<tag>.*?)(?::(?<val>.*?))?=(?<text>.*?)}