2

我有以下代码:

void Main()
{
  string template = @"
aaa 
{begin iteration items} 
  bbbbbb 
  {begin iteration subitems} 
    ccccccc 
  {end iteration subitems} 
  ddddddddd 
  {begin iteration items} 
    hhhhhhhhhhhhhhhhh
  {end iteration items} 
  iiiiiiiiiiiiiiiiiiiiiiiiiiii
{end iteration items} 
eeeeeeeeeeeeeeee
{begin iteration items} 
  ffffff
{end iteration items} 
gggggggggggg
  ";

  string re = @"
\{\s*begin\s+iteration\s+items\s*}
(?<template>
  (
    (?<iteration>\{\s*begin\s+iteration\s+items\s*})
    |(?<-iteration>\{\s*end\s+iteration\s+items\s*})
    |((?!(\{\s*begin\s+iteration\s+items\s*})|(\{\s*end\s+iteration\s+items\s*})).*?)
  )*(?(iteration)(?!))
)
\{\s*end\s+iteration\s+items\s*}
  ";

  Regex r = new Regex(re, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace);
  var matches = r.Matches(template);
  matches.Dump();
}

template平衡时,则返回匹配项,一切正常。但是当我在模板中更改{end iteration items}{end1 iteration items}iiiiiiiiiiiiiii行时,代码停止在线响应matches.Dump()Dump()是在 LinQPad 中读取/枚举的扩展方法)

怎么了?是否可以重写正则表达式以使其始终响应?

编辑 我的目标是如果语法有效则捕获所有顶级<template>组,否则不捕获任何内容。我按照卢卡斯的建议尝试了非回溯组,但是当语法有效时,现在没有捕获。

4

1 回答 1

2

你在这里经历了灾难性的回溯

简而言之:((something)*)*带有嵌套量词形式的模式将触发它,因为如果无法立即找到匹配项,引擎必须尝试所有可能的组合。

您可以使用原子组来防范它。以下应该可以解决问题:

\{\s*begin\s+iteration\s+items\s*}
(?<template>
  (?>
    (?<iteration>\{\s*begin\s+iteration\s+items\s*})
    |(?<-iteration>\{\s*end\s+iteration\s+items\s*})
    |[^{]+
    |\{
  )*(?(iteration)(?!))
)
\{\s*end\s+iteration\s+items\s*}

或者使用((?>...))而不是(?>...)如果您需要捕获。

我简化了表达式 - 使用原子组时不再需要前瞻,因为这些情况将由iteration组处理。替代项 ( ) 的最后一部分\{是为了说明单独的左大括号,它们不是开始/结束序列的一部分。大多数文本被[^{]+原子组内部消耗,因此不会发生回溯。

于 2015-07-31T14:07:10.420 回答