嵌套相同条件时,正则表达式不起作用

时间:2019-01-23 14:07:30

标签: c# regex

背景:我只是在摆弄一个简单模板的想法,该想法仅提供if / for / render,以了解它的可行性以及在我的个人项目中使用是否有意义。与使用NVelocity或Razor或其他任何工具相对。

我写了一个正则表达式:

(?:(?:(?<open>\[if (?<if>[a-zA-Z0-9\.]+)\])(?<content>[^\[]*))+(?:[^\[]*(?<close-open>\[end if\]))+)+(?(open)(?!))

当与示例文本一起使用时:

<div>
[if variable3]{{variable3}}[end if]
</div>

<div>
[if variable1]

    {{variable1}}

    [if variable2]
        <br>
        {{variable2}}
    [end if]

[end if]
</div>

工作正常。我得到2个匹配项,如果第二个匹配项有效,则可以解析内部捕获。

问题是如果我有多个嵌套匹配项。因此给出:

<div>
[if variable3]{{variable3}}[end if]
</div>

<div>
[if variable1]

    {{variable1}}

    [if variable2]
        <br>
        {{variable2}}
    [end if]

    [if variable4]
        <br>
        {{variable4}}
    [end if]

    [if variable5]
        <br>
        {{variable5}}
    [end if]

[end if]
</div>

我最终得到的是第一个捕获是正确的,然后是所有3个单独的捕获,而不是第二个匹配的外部捕获。

如果我扩展捕获以忽略内部内容的\[,它将导致第一和第二个匹配项合并为一个匹配项。 :(

有人知道如何解决此问题吗? (如果您对模板的制作方法有更好的了解,请在评论中了解)

1 个答案:

答案 0 :(得分:1)

您可以使用

@"(?s)\[if\s+(?<if>[^][]+)](?<fullBody>(?>(?:(?!\[if\s|\[end\ if]).)+|(?<-open>)\[end\ if]|(?<open>)\[if\s+(?<if>[^][]+)])*(?(open)(?!)))\[end\ if]"

请参见regex demo

详细信息(请注意,由于x修饰符,您可以在C#代码中使用它)

@"(?sx)               # Singleline and IgnorePatternWhitespace flags on
  \[if\s+             # "[if" and then 1+ whitespaces
    (?<if>[^][]+)     # "If" group: one or more chars other than "]"
  ]                   # a "]" char
   (?<fullBody>       # Group "fullBody" containing all nested if blocks
     (?>              # Start of an atomic group
       (?:(?!\[if\s|\[end\ if]).)+|    # any char, 1+ occurrences, that does not start the "[if " or "[end if]" substring, or...
       (?<-open>)\[end\ if]|           # "[end if]" substring and an item is popped from Group "open", or
       (?<open>)\[if\s+(?<if>[^][]+)]  # Group "open": "[if", 1+ whitespaces, Group "if": 1+ chars other than "[" and "]", and then a "]" char
     )*               # repeat atomic group patterns 0 or more times
     (?(open)(?!))    # A conditional: if Group "open" has any items on its stack, fail and backtrack
   )                  # End of fullBody group
  \[end\ if]"         # "[end if]" substring

如果您不关心if块是否嵌套在哪个块中,则可以使用此正则表达式的变体清楚地获得if块的完整列表:

var pattern = @"(?s)(?=(?<ifBlock>\[if\s+(?<if>[^][]+)](?<fullBody>(?>(?:(?!\[if\s|\[end\ if]).)+|(?<-open>)\[end\ if]|(?<open>)\[if\s+(?<if>[^][]+)])*(?(open)(?!)))\[end\ if]))";

上面的模式只是被另一个命名的捕获组包裹,并置于正向内部。虽然匹配值始终为空,但组将保留您可能需要的所有值。