【问题标题】:Looking for a string that is not inside another string pattern寻找不在另一个字符串模式内的字符串
【发布时间】:2012-11-22 10:28:32
【问题描述】:

我正在使用专有语言实现经典的if, else, endif

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


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

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

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

【问题讨论】:

  • [!--@Else--] 没有出现在 [!--@If--]...[!--@EndIf--] 块内。您是指[!--@Else--] 的最外层出现吗?
  • @Asad - 是的,当然。从最外面的 if/else 内部开始,找到不在嵌套 if/else 内部的 else。
  • 哪种语言...?正则表达式的实现因语言而异
  • 你试过“平衡组”:blog.stevenlevithan.com/archives/balancing-groups 吗?本文后面的示例似乎有助于解决您的问题。

标签: .net regex regex-lookarounds


【解决方案1】:

正如 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.

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

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

  1. 我不允许在If 条件中使用任何类型的括号。如果你想这样做,你也必须检查它们的正确的嵌套。它比我在这里做的稍微简单一些,但它仍然需要上下一堆括号。
  2. 主要问题可能是实际匹配[\[]]*。由于我不允许任何类型的左括号,您不能在 Else 块中包含条件语句。现在,如果您想允许这样做,您必须将几乎整个内容再次复制到实际匹配中,以便您知道哪些Ifs 和EndIfs Else 和哪些在之后。

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

【讨论】:

  • 非常感谢。实际上,我现在已经平衡并运行,并且有一个“足够好”的解决方案。它不是防弹的,因为你写起来很困难。
  • (?>(?!|).|(?)|(?))* (?(Depth)(?!))
  • @user1844646 如果你想在你的生产代码中使用这样的东西,你需要使用IgnorePatternWhitespace,像我的答案一样格式化并添加cmets。没有人能够理解这一点(即使你一个人在做这个项目;到圣诞节你会忘记它的详细作用)
【解决方案2】:

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-27
    • 2014-02-23
    • 2021-03-13
    • 2014-11-10
    • 1970-01-01
    • 1970-01-01
    • 2022-06-17
    • 1970-01-01
    相关资源
    最近更新 更多