匹配包含{word}但不包含{secondword}的文字

时间:2013-08-15 07:30:06

标签: c# python regex

我写了一个正则表达式(经过一些很好的帮助here),它过滤了python文件中的所有函数。所以现在,我的老板只想要包含 OpenSession 但不包含 Session.Close()的函数。

我读了article about Lookarounds,但说实话,即使经过多次阅读,我也无法使用它。但我认为它普遍缺乏正则表达式的理解。无论...

我的尝试全部失败,最后一次尝试失败:(?is)def\s*(?<name>\w+)\s*\((?<parameter>[^)]+)\)\s*:\s*(?:\r?\n)+(?<body>(?<=OpenSession?).*?(?=Session\.Close?))(?=\r?\ndef|$)

有人可以帮助我,也许可以解释一下这些步骤,我可以从中学习吗?

1 个答案:

答案 0 :(得分:5)

获取所有函数然后根据它们是否包含OpenSession并且不包含Session.Close()来过滤它们肯定会更容易(更易读,更易于维护)。虽然有可能。我只关注你表达的body部分。要检查是否有OpenSession即将到来,我们会将其设置为提前。但是前瞻只检查当前位置,所以我们需要在两者之间允许任意多个字符:

(?=.*OpenSession)

问题是,这可能会在下一个函数中找到OpenSession。因此,我们需要确保.*无法通过下一个def。要做到这一点,在使用每个字符之前,我们需要检查它是否标记def的开头(与另一个否定前瞻):

(?=(?:(?!def).)*OpenSession)

所以现在模式不匹配函数,如果它不包含OpenSession。为了排除包含Session.Close的函数,我们使用了与前瞻中使用的类似技巧。我们尝试进入下一个def,而不会超越Session.Close

(?=(?:(?!def).)*OpenSession)(?:(?!Session[.]Close).)*?

原始图案末尾的前瞻将确保您能够以这种方式使用整个功能体。另请注意,通过避免非贪婪的重复,您可以略微提高性能。您可以通过将def添加到第二个前瞻来完成此操作:

(?=(?:(?!\r?\ndef).)*OpenSession)(?:(?!Session[.]Close|\r?\ndef).)*

所以表达式看起来像:

(?is)def\s+(?<name>\w+)\s*\((?<parameter>[^)]+)\)\s*:\s*(?:\r?\n)+(?<body>(?=(?:(?!\r?\ndef).)*OpenSession)(?:(?!Session[.]Close|\r?\ndef).)*)(?=\r?\ndef|$)

我不知道你想要在你的外观结束时用?完成什么,但他们所做的就是让最后一个角色成为可选的。

另请注意,模式通常有点危险,因为函数中可能包含多行字符串,其中包含\ndef,在这种情况下,正则表达式不会返回整个函数。

正如HamZa在评论中提到的那样,您可能希望在每个\bOpenSessionSession.Close周围添加单词边界def,以免绊倒{ {1}},getOpenSession()Session.Closed