.net 查找不在其他字符串模式中的字符串
我有一个用专有语言实现的经典.net 查找不在其他字符串模式中的字符串,.net,regex,regex-lookarounds,.net,Regex,Regex Lookarounds,我有一个用专有语言实现的经典if,else,endif 如果我有下面的字符串,我想定位[!-->Else-->语句,但只定位[!-->If-->…[!-->@EndIf-->]块中而不是的语句。因此,我希望在匹配else之前,打开和关闭ifs的次数为偶数 乱数假文 [!-->@如果(1=1)--] 是的 [!-->@如果(2=1)--] 2不是1 [!-->@其他--] 这样做吧 [!-->@EndIf--> [!-->@其他--] 1不是1 [!-->@EndIf--> 还有别的 在本例中
if,else,endif
如果我有下面的字符串,我想定位[!-->Else-->
语句,但只定位[!-->If-->…[!-->@EndIf-->]
块中而不是的语句。因此,我希望在匹配else
之前,打开和关闭if
s的次数为偶数
乱数假文 [!-->@如果(1=1)--] 是的 [!-->@如果(2=1)--] 2不是1 [!-->@其他--] 这样做吧 [!-->@EndIf--> [!-->@其他--] 1不是1 [!-->@EndIf--> 还有别的
在本例中,我想定位第二个
else
,而不是第一个,因为它位于if/endif
块内
我现在已经花了无数个小时与消极和积极的期待落后,无法让它工作 您可以使用此正则表达式作为匹配组
值的一部分来检索每个if块的内容。最外层的匹配是阵列中的最后一个匹配:
(?<=\bif)(?>if(?<DEPTH>)|(?<VALUE-DEPTH>)endif|.?)*(?(DEPTH)(?!))(?=endif\b)
正如Abbondanza所提到的,如果您想用正则表达式实现这一点,您将需要平衡组。我应该警告你,这不是一个好的解决方案。尽管.NET的regex引擎是少数能够处理此类情况的引擎之一,但它仍然不是真正推荐的方法。您最好手动解析您的语言,这样可以更轻松地计算嵌套级别
无论如何,为了向您说明为什么正则表达式不适合在生产性软件中执行此任务,这里有一个regex(使用RegexOptions.IgnorePatternWhitespace
和RegexOptions.Singleline
),它仍然做出了一些简化的假设(稍后我将讨论):
(?#为后面可能出现的任何内容启动子模式并
#抑制回溯(因为备选方案是
#互斥)
(?\[!-->If\([^()]*\)--\])
#如果遇到If块,请将新捕获推到
#堆栈(因为嵌套级别升高)
|#或
(?)\[!-->@EndIf--\]
#如果我们可以从堆栈中弹出一个捕获,则使用
#EndIf。如果我们不能,命名组将失败。因此
#我们只能消耗比现在更多的一端
#遇到国际单项体育联合会。
|#或
(?!\[!-->@EndIf--\])。#如果此字符未标记
#EndIf,使用任意字符。
)*#尽可能长时间地重复。
$#确保我们已经到达了字符串的末尾。
(?(深度)(?!)#如果堆栈上还有任何内容,也会失败,
#因为有些Ifs没有关闭,所以
#语法无论如何都是无效的。
#如果你说服了自己,你可以省去这个
#在此之前,请确保整个嵌套语法是正确的。
)#展望结束。
现在这已经是一头野兽了,如果没有这本评论小说,几乎没有人会理解
但我提到了简化假设。给你
我不允许在If
条件中使用任何类型的括号。如果您想这样做,您还必须检查它们的正确嵌套。它比我在这里做的稍微简单一些,但仍然需要上下构建一堆括号
主要问题可能是实际的匹配[\[]]*
。由于我不允许任何类型的左括号,因此在Else
块中不能有条件语句。现在,如果您想允许这样做,您必须将几乎整个内容再次复制到实际匹配中,以便您知道哪些if
s和EndIf
s在Else
中,哪些在后面
你看,要得到一个100%覆盖所有情况的正则表达式解决方案,你需要使代码完全不可维护。这就是为什么你应该认真考虑,分析字符串手动和建立某种语法树。通过这种方式,您可以获得嵌套结构的OOP表示,可以轻松地为要查找的特定Else
遍历这些嵌套结构。在[!-->Else-->]
块中没有出现[!-->If-->]…[!-->EndIf-->]
块。你是说最外面出现的[!-->@Else-->
?@Asad-当然是的。从最外层的if/else内部开始,找到嵌套if/else中没有的else。哪种语言。。。?不同语言的正则表达式实现不同您是否尝试过“平衡组”:?本文后面的示例对于解决您的问题似乎很有用。非常感谢。事实上,我现在已经完成了平衡,并且有了一个“足够好”的解决方案。它不是防弹的,因为你写起来很难。(?>(?!)。(?)(?)(?)*(?(深度)(?!)@user1844646如果你想在你的产品代码中使用这样的东西,你需要使用IgnorePatternWhitespace
,像我的答案一样格式化,并添加注释。没有人能够理解这一点(即使你一个人在做这个项目;到了圣诞节,你会忘记它的细节)
(?<=\bif)(?>if(?<DEPTH>)|(?<VALUE-DEPTH>)endif|.?)*(?(DEPTH)(?!))(?=endif\b)
(?<=else)((?!else).)+$
(?<=\[!--@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.