2

我写了一个正则表达式(在这里得到了一些很大的帮助),它从 python 文件中过滤所有函数。所以现在,我的老板只想要包含OpenSession而不是Session.Close()的功能。

我读过关于 Lookarounds 的文章,但说实话,即使读了很多遍,我也无法适应它。但我认为它普遍缺乏对正则表达式的理解。任何...

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

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

4

1 回答 1

5

获取所有函数,然后根据它们是否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.Closeddefine

于 2013-08-15T08:49:07.937 回答