如何在字符串中匹配多字符包装器?

时间:2014-05-28 23:16:37

标签: .net regex

我会努力做到这一点简单易行,因为我很难说出我正在尝试做什么。

基本上我正在尝试匹配令牌内的令牌或整个令牌。我下面的正则表达式有效,除非有一个随机{不是令牌的一部分。

示例:

Tokens start with "{:" and end with ":}"
{:MyTokenFunction({:MyTokenParameter:}):} 
^--- WORKS as it matches "{:MyTokenParameter:}"

{:MyTokenFunction(5):} 
^--- WORKS as it matches "{:MyTokenFunction(5):}"

{:MyTokenFunction(random{string}):} 
^--- The "{" causes no matches, but should match the entire string.

这是我所匹配的正则表达式的一个彩色示例。 *前两个例子是正确的,但第三个例子应该完全匹配,它根本不匹配。 enter image description here

这是我正在使用的正则表达式,它与第三个例子有问题:

\{\:[^\{]+?\:\}

对于我的生活,我无法弄清楚如何绕过造成0场比赛的{

我尝试使用lookbehinds / aheads,但我没有太多运气。虽然我当然喜欢快速回答;我想要解释正则表达式实际上做得更多。我做了很多搜索试图弄清楚这一点,但由于我的“标记”被多个字符包裹并且开始/结束不一样,所以无法找到一个好例子。

由于

2 个答案:

答案 0 :(得分:2)

您的正则表达式匹配以{:开头的字符串,以:}结尾,并且之间没有任何{。请注意?之后显示的+,这会使其变得非贪婪。它上面有很多文档。

在你的情况下,

{:MyTokenFunction(random{string}):} 

中间有{string}部分,由于花括号而拒绝它。

如果这是一个有效的字符串,那么该条件不应该存在,应该取出。例如

\{\:.+?\:\}

但是,如果该条件是限制,那么您的字符串无效输入。

答案 1 :(得分:2)

这是一个可爱的问题,因为它需要我们平衡开始和结束令牌,这是一个.NET恰好具有现成功能的任务:平衡组。

让我们分别看一下。

为什么你的正则表达式不起作用?

[^\{]+表示"匹配任何数量不是{"

的字符

显然,这无法匹配{中的{3}

简单解决方案(有警告)

{:.*:}

这将贪婪地匹配开始和结束大括号之间的所有内容。如果每行只有一个标记(如果您不处于DOTALL模式),则此方法有效。

但是,如果你在同一行上有两个令牌,那么正则表达式会同时使用它们。如果您处于DOTALL模式,这将占用所有令牌。这就是你要知道的。

请参阅demo

更复杂(但更强大)的解决方案

为了避免上述问题,我们需要平衡大括号。在Perl或PCRE中,我们将使用递归。由于我们在.NET中,我们将使用平衡组,这是.NET引擎的一个很好的功能。

这是一种方法。这是一个满口的,但我会在下面解释。

(?:{:(?<counter>)(?:(?!{:|:}).)*)+(?::}(?<-counter>)(?:(?!{:|:}).)*)+(?<=:})(?(counter)(?!))

请参阅demo

这是如何运作的?

这是相同的正则表达式,但在自由间隔模式下,带有注释。我建议在代码中使用此版本,因为它使维护更容易。

(?x) # free-spacing mode
(?:{:(?<counter>)(?:(?!{:|:}).)*)+ # match all the opening {: and increment counter
(?::}(?<-counter>)(?:(?!{:|:}).)*)+ # # match all the closing {: and decrement counter
(?<=:}) # negative lookbehind: we must close tiwht a :} (backtrack if we went too far)
(?(counter)(?!)) # if the counter has not been decremented to zero, then fail (ensuring balance)

潜在调整

根据您的需要,可能存在调整:例如,如果您希望令牌能够跨越多行。请告诉我们。