我写了一个正则表达式(经过一些很好的帮助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|$)
有人可以帮助我,也许可以解释一下这些步骤,我可以从中学习吗?
答案 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在评论中提到的那样,您可能希望在每个\b
,OpenSession
和Session.Close
周围添加单词边界def
,以免绊倒{ {1}},getOpenSession()
和Session.Closed
。