背景:我只是在摆弄一个简单模板的想法,该想法仅提供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个单独的捕获,而不是第二个匹配的外部捕获。
如果我扩展捕获以忽略内部内容的\[
,它将导致第一和第二个匹配项合并为一个匹配项。 :(
有人知道如何解决此问题吗? (如果您对模板的制作方法有更好的了解,请在评论中了解)
答案 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]))";
上面的模式只是被另一个命名的捕获组包裹,并置于正向内部。虽然匹配值始终为空,但组将保留您可能需要的所有值。