首页 > 解决方案 > 捕获外部括号/括号组,同时忽略内部括号组

问题描述

这是我之前的 SO question的排列。答案对我来说非常有效,直到我遇到导致问题的边缘情况。我现在需要一个经过调整的正则表达式模式。我曾尝试在Regex Storm自己解决这个问题,但我对 regex 的了解还不够先进。

与我之前的帖子(上面链接)的一个变化是,我现在只对匹配以开头([而不是仅开头的括号分组感兴趣(。分组的结尾保持不变:)

为了完整起见,这里是整个之前的问题,针对新要求进行了修改:

我正在使用 C# 和正则表达式,尝试捕获外部括号组而忽略内部括号组。我有旧版生成的文本文件,其中包含数千个字符串结构,如下所示:

([txtData] of COMPOSITE
(dirty FALSE)
(composite [txtModel])
(view [star3])
(creationIndex 0)
(creationProps )
(instanceNameSpecified FALSE)
(containsObject nil)
(sName txtData)
(txtDynamic FALSE)
(txtSubComposites )
(txtSubObjects )
(txtSubConnections )
)

([txtUI] of COMPOSITE
(dirty FALSE)
(composite [txtModel])
(view [star2])
(creationIndex 0)
(creationProps )
(instanceNameSpecified FALSE)
(containsObject nil)
(sName ApplicationWindow)
(txtDynamic FALSE)
(txtSubComposites )
(txtSubObjects )
(txtSubConnections )
)

([star38] of COMPOSITE
(dirty FALSE)
(composite [txtUI])
(view [star39])
(creationIndex 26)
(creationProps composite [txtUI] sName Bestellblatt)
(instanceNameSpecified TRUE)
(containsObject COMPOSITE)
(sName Bestellblatt)
(txtDynamic FALSE)
(txtSubComposites )
(txtSubObjects )
(txtSubConnections )
)

我正在寻找一个将捕获上面示例中的 3 个分组的正则表达式,这是上一个 SO 帖子中的解决方案:

Regex regex = new Regex(@"\((?>\((?<c>)|[^()]+|\)(?<-c>))*(?(c)(?!))\)"); 
return regex.Matches(str);

我需要对上面的正则表达式模式稍作调整,以便它只匹配以 开头的分组,([而不仅仅是以(. 结局还是一样:)

需求匹配很简单:

  1. 左括号 + 方括号 ( ([) 要么是文件中的第一个字符,要么跟在newline.
  2. 右括号是文件中的最后一个字符,或者后跟一个newline.

我希望正则表达式模式忽略所有不遵守上述数字 1 和 2 的括号分组。“忽略”我的意思是它们不应该被视为匹配 - 但它们应该作为外部分组匹配的一部分返回。

因此,为了实现我的目标,当我的 C# 正则表达式针对上面的示例运行时,我应该返回一个MatchCollection恰好有 3 个匹配项的正则表达式,如上所示。

它是如何完成的?

标签: c#regexregex-group

解决方案


您可以在模式开始时应用正向前瞻,这需要[在初始(. 此外,由于前导([只能出现在行首,而结束只能出现在行尾,因此添加和锚点)是有意义的(注意是必要的,因为在多行模式中仅匹配位置 before ,而不是 before )。^\r?$\r?$\n\r

因此,您的正则表达式可能会调整为

var results = Regex.Matches(text, 
                  @"^\((?=\[)(?>\((?<c>)|[^()]+|\)(?<-c>))*\)\r?$", 
                  RegexOptions.Multiline)
              .Cast<Match>()
              .Select(x => x.Value)
              .ToList();

请参阅.NET 正则表达式演示

细节

  • ^- 一行的开始
  • \(- 一个(字符
  • (?=\[)- a[应该立即跟随当前位置
  • (?>\((?<c>)|[^()]+|\)(?<-c>))*- 0次或多次重复
    • \((?<c>)|-(一个空值被压入`Group "c" 捕获栈,或者
    • [^()]+|- 0 个或多个除(and以外的字符),或
    • \)(?<-c>)-)并且从“组”c“捕获堆栈中弹出一个空值
  • \)- 一个)字符
  • \r?$- 可选的 CR 和行尾。

推荐阅读