获取所有函数,然后根据它们是否OpenSession
包含Session.Close()
. 这是可能的。我body
这里只关注你表达的那部分。为了检查是否有OpenSession
到来,我们将其放入前瞻中。但是前瞻只检查当前位置,所以我们需要在两者之间允许任意多个字符:
(?=.*OpenSession)
问题是,这可以OpenSession
在下一个函数中找到。所以我们需要确保.*
不能超过下一个def
。为此,在使用每个字符之前,我们需要检查它是否没有标记 a 的开头def
(带有另一个负 前瞻):
(?=(?:(?!def).)*OpenSession)
所以现在模式不会匹配一个函数,如果它不包含OpenSession
. 为了排除包含 的函数Session.Close
,我们使用了与前瞻中使用的类似的技巧。我们试图在def
不超越 a的情况下进入下一个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 在评论中提到的,您可能希望\b
在每个OpenSession
,Session.Close
和周围设置单词边界def
,以免绊倒getOpenSession()
,Session.Closed
和define
。