寻找不在另一个字符串模式中的字符串

时间:2012-11-22 10:28:32

标签: .net regex regex-lookarounds

我使用专有语言进行经典if, else, endif实现。

鉴于我有下面的字符串,我想找到[!--@Else--]语句,但只找到[!--@If--]...[!--@EndIf--]块中 NOT 的语句。因此,在匹配if之前,我想要偶数个开头并关闭else ...


Lorem ipsum
[!--@If(1=1)--]
One it is
    [!--@If(2=1)--]
        2 is not 1
    [!--@Else--]
        so do this
    [!--@EndIf--]
[!--@Else--]
1 is not 1
[!--@EndIf--]
and something else

在这个例子中,我想找到第二个else - 而不是第一个,因为它位于if/endif块内。

我现在已经花费了无数个小时的消极和积极的观察,并且无法让它发挥作用!?

2 个答案:

答案 0 :(得分:0)

您可以使用此正则表达式来检索每个if块的内容,作为匹配组VALUE的一部分。最外面的匹配是数组中的最后一个:

(?<=\bif)(?>if(?<DEPTH>)|(?<VALUE-DEPTH>)endif|.?)*(?(DEPTH)(?!))(?=endif\b)

请注意,为清楚起见,我使用ifendif来表示您的开始和结束语法。

然后,您可以在组中的最后一个值上使用此正则表达式来提取else子句:

(?<=else)((?!else).)+$

答案 1 :(得分:0)

正如Abbondanza所说,如果你想用正则表达式做这个,你需要平衡组。我应该警告你,这不是一个好的解决方案。虽然.NET的正则表达式引擎是为数不多的,可以处理这样的情况,但它仍然不是真正推荐的方法。您可能最好手动解析语言,这样可以更轻松地计算嵌套级别。

无论如何,只是为了告诉你,为什么正则表达式不适合生产软件中的这个任务,这里有一个正则表达式(使用RegexOptions.IgnorePatternWhitespaceRegexOptions.Singleline)仍然做出一些简化的假设(我会到了以后):

(?<=\[!--@Else--\])      # Make sure that our match begins right after an else
                         # block.
[^\[]*                   # Match as many non-[ characters as possible (the actual
                         # statement)
(?=                      # This lookahead will assert that the previous statement
                         # was a top-level Else
  (?<Depth>)             # Push one capture onto the stack "Depth" (because, if
                         # this is one of the desired "Else"s we are exactly one
                         # level deep
  (?>                    # Start a subpattern for anything that could follow and
                         # suppress backtracking (because the alternatives are
                         # mutually exclusive)
    (?<Depth>\[!--@If\([^()]*\)--\])
                         # If we encounter an If block, push a new capture onto
                         # the stack (because the nesting level rises)
  |                      # OR
    (?<-Depth>)\[!--@EndIf--\]     
                         # IF we can pop a capture from the stack, consume an 
                         # EndIf. If we cannot, the named group will fail. Hence
                         # we can only consume one EndIf more than we already
                         # encountered Ifs.
  |                      # OR
    (?!\[!--@EndIf--\]). # If this character does not mark the beginning of an
                         # EndIf, consume an arbitrary character.
  )*                     # Repeat as long as possible.
  $                      # Make sure we have reached the end of the string.
  (?(Depth)(?!))         # If there is anything left on the stack, fail, too,
                         # because there are some Ifs that were not closed, so
                         # the syntax was invalid anyway.
                         # You can leave this out if you have convinced yourself
                         # beforehand that the overall nesting syntax is correct.
)                        # End of lookahead.

现在这已经是一头野兽,如果没有这篇评论小说,几乎没有人会理解。

但我提到简化假设。你走了。

  1. 我不允许在If条件下使用任何类型的括号。如果你想这样做,你也必须检查他们的正确的嵌套。它比我在这里做的稍微简单一些,但它仍然需要在一堆括号中构建和放下。
  2. 主要问题可能是实际匹配[\[]]*。由于我不允许使用任何类型的左括号,因此Else块内不能包含条件语句。现在,如果您想允许这样做,您必须将几乎所有内容复制到实际匹配中,以便了解哪些IfEndIf Else以及之后发生的事情。
  3. 您可以看到,要获得覆盖100%所有案例的正则表达式解决方案,您需要使该代码完全无法维护。这就是你应该考虑的原因,手动分析字符串并构建某种语法树。通过这种方式,您可以获得嵌套结构的OOP表示,可以轻松遍历您想要查找的特定Else