2

我有if, else, endif一个专有语言的经典实现。

鉴于我有下面的字符串,我想找到该[!--@Else--]语句,但只找到不在块内的那个[!--@If--]...[!--@EndIf--]。所以我想要偶数的ifs 在匹配之前打开和关闭else...


Lorem ipsum
[!--@If(1=1)--]
一个是
    [!--@If(2=1)--]
        2 不是 1
    [! - @别的 - ]
        所以这样做
    [! - @万一 - ]
[! - @别的 - ]
1 不是 1
[! - @万一 - ]
和别的东西

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

我现在已经花了无数个小时进行消极和积极的回顾,但无法让它发挥作用!?

4

2 回答 2

0

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

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

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

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

(?<=else)((?!else).)+$
于 2012-11-22T13:36:14.347 回答
0

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

无论如何,只是为了向您展示,为什么正则表达式不适合生产软件中的这项任务,这里有一个正则表达式(使用RegexOptions.IgnorePatternWhitespaceand RegexOptions.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块内包含条件语句。现在,如果您想允许这样做,您必须将几乎整个内容再次复制到实际匹配中,以便您知道哪些Ifs 和EndIfs 在里面Else,哪些在后面。

您会看到,要获得涵盖 100% 所有情况的正则表达式解决方案,您需要使该代码完全不可维护。这就是为什么您应该真正考虑手动分析字符串并构建某种语法树的原因。通过这种方式,您可以获得嵌套结构的 OOP 表示,可以轻松遍历Else您想要查找的特定 s。

于 2012-11-22T14:13:13.207 回答