如何使用正则表达式来查找函数调用自己?

时间:2012-01-04 03:00:27

标签: python regex shell awk

我有code.py

def funA():
    print('A')
    funA()

def funB():
    print('B')

def funC():
    print('C')
    funB()
    funC()

我想找到所有函数自称:

funA
funC

如何撰写regex

约束:

  • 所有函数调用都是正常的:funname(arg1, arg2, ...)
  • 没有混淆的方式(例如lambdaexec
  • 无间接递归

5 个答案:

答案 0 :(得分:2)

这很难,因为该函数可以用混淆的方式调用自己。例如,这算了吗?

def funA():
  print 'A'
  foo = funA
  foo()

funA()

这个怎么样?

def funA():
  funB()

def funB():
  funA()

funA()

甚至是这个?

def funA():
  exec('Anuf'[::-1] + '()')

funA()

我认为你不能用正则表达式做到这一点。


即使考虑到您的新编辑,如果不是不可能的话,仍然会非常困难。例如,考虑这个功能。

def funA():
  if 1 + 1 == 2:
    return
  funA()

我建议您遵循Ignacio Vazquez-Abrams的建议并查看ast

答案 1 :(得分:1)

简单地说,你将无法用正则表达式做到这一点。您至少需要解析函数定义,保留当前正在解析的函数的某种状态,并在当前函数的范围内搜索当前函数名的调用。

答案 2 :(得分:1)

是的我确实认为正则表达式不可能匹配wim指出的自我调用被混淆的情况。但是,这里有一个正则表达式,可以为简单的自我调用做一个半体面的工作(格式为funcname(...))。此正则表达式正确匹配原始问题中拼写的所有测试用例:

reobj = re.compile(r"""
    # Match (unreliably) Python function with self reference.
    ^                        # Anchor to start of line.
    ([ \t]*)                 # $1: Indentation of DEF statement.
    def[ \t]+                # Function definition.
    ([^\s(]+)                # $2: Name of function to find.
    .*\r?\n                  # Remainder of function def line.
    (?:                      # Zero or more lines w/o funcname.
      (?:                    # Function block lines alternatives.
        \1[ \t]+             # Func block lines have extra indentation.
        (?:(?!\b\2\s*\().)*  # Optional non-funcname stuff on line
      | [ \t]*\#.*           # Allow comment lines to defy indent rules.
      )?                     # Allow blank lines in function block.
      \r?\n                  # End of line not containing funcname.
    )*                       # Zero or more lines w/o funcname
    \1[ \t]+                 # Now match the line having funcname.
    (?:(?!\b\2\s*\().)*      # Optional non-funcname stuff on line
    \b\2\s*\(                # Match the function self reference.
    """, re.MULTILINE | re.VERBOSE)

它与函数定义行匹配,并在组'def'中的$1和组$2中的函数名称之前捕获空白缩进。然后它匹配功能块中不包含函数名的行,每个函数名都有比函数定义更多的前导空格。它跳过空行和仅包含注释的行。一旦它在功能块中找到一行,其后面有一个左括号,表示对它自己的调用,它就会声明一个匹配。否则,它声明不匹配,然后继续寻找下一个可能的匹配。

请注意,此解决方案不可靠,如果函数名称出现在字符串内或符合行上其他代码的注释内,则会导致误报。它也不处理多行原始字符串的函数。但是,它会正确地捕获一些!

答案 3 :(得分:0)

我将描述我认为你想要的模式:一行以def开头,后跟空格,后跟一个名称(你在括号中捕获),后跟一组(可能是空的)行开始使用空格,后跟一行以空格开头并包含您的函数名称后跟一个打开的paren(以便捕获实际的调用,而不仅仅是引用)。

答案 4 :(得分:0)

可能你可以使用gawk,下面是我的示例代码,你可能需要修改它:

#! /usr/bin/gawk -f
{
    currentLine = $0
    if (currentLine ~ /def/){
        inFunction = "true"
        nameIndex = index($2,"(")
        functionName = substr($2,1,nameIndex - 1)
        #print functionName
        next
    }
    if (inFunction == "true" && currentLine ~ functionName){
       inFunction = false 
       print "recursive function is: " functionName
    }
}

只需运行程序就可以得到你想要的东西。