与Python函数调用匹配的正则表达式
我想在Python中创建一个正则表达式,它将匹配Python源代码中的一行并返回函数调用列表。与Python函数调用匹配的正则表达式
典型的线路是这样的:
something = a.b.method(time.time(), var=1) + q.y(x.m())
,其结果应该是:
["a.b.method()", "time.time()", "q.y()", "x.m()"]
我这里有两个问题:
- 创建正确的模式
- 捕获组重叠
谢谢大家帮忙
我不认为正则表达式是最好的方法。考虑ast module代替,例如:
class ParseCall(ast.NodeVisitor):
def __init__(self):
self.ls = []
def visit_Attribute(self, node):
ast.NodeVisitor.generic_visit(self, node)
self.ls.append(node.attr)
def visit_Name(self, node):
self.ls.append(node.id)
class FindFuncs(ast.NodeVisitor):
def visit_Call(self, node):
p = ParseCall()
p.visit(node.func)
print ".".join(p.ls)
ast.NodeVisitor.generic_visit(self, node)
code = 'something = a.b.method(foo() + xtime.time(), var=1) + q.y(x.m())'
tree = ast.parse(code)
FindFuncs().visit(tree)
结果
a.b.method
foo
xtime.time
q.y
x.m
“ast”模块上的+1教程!很高兴知道它提供的东西比'literal_eval'更有用:) :) – 2011-12-28 19:41:33
事实上,除非我错了,否则基于正则表达式的方法注定要失败。 Python语言基于上下文无关语法,并且(除非我错了),CFG比正则表达式更具表现力(谢谢[Chomsky Hierarchy](http://en.wikipedia.org/wiki/) Chomsky_hierarchy) – 2012-09-10 17:22:59
@AdamParkin:[这个问题]的一些答案(http://stackoverflow.com/questions/11306641/what-kind-of-formal-languages-can-modern-regex-engines-parse)可能是有趣的你 – georg 2012-09-10 18:00:22
/([.a-zA-Z]+)\(/g
应该匹配方法名;因为你有一些嵌套后你必须添加parens。
'foo(“bar(a,b)”)'会为该正则表达式错误地返回'bar'。 – 2011-12-28 16:42:37
@DouglasLeeder公平点。 – Mathletics 2011-12-28 16:49:17
@DouglasLeeder它看起来不错,但[this](http://pastebin.com/7dKpRh5B)Python代码不能打印预期的内容。 – xralf 2011-12-28 17:35:51
我真的不知道Python,但我可以想像,使这项工作正常涉及一些并发症,如:
- 串
- 评论
- 表达式返回一个对象的
但是对于您的示例,像这样的表达式有效:
(?:\w+\.)+\w+\(
$ python3
>>> import re
>>> from itertools import chain
>>> def fun(s, r):
... t = re.sub(r'\([^()]+\)', '()', s)
... m = re.findall(r'[\w.]+\(\)', t)
... t = re.sub(r'[\w.]+\(\)', '', t)
... if m==r:
... return
... for i in chain(m, fun(t, m)):
... yield i
...
>>> list(fun('something = a.b.method(time.time(), var=1) + q.y(x.m())', []))
['time.time()', 'x.m()', 'a.b.method()', 'q.y()']
我为你证明这一点的例子是在Python3可行
import re def parse_func_with_params(inp): func_params_limiter = "," func_current_param = func_params_adder = "\s*([a-z-A-Z]+)\s*" try: func_name = "([a-z-A-Z]+)\s*" p = re.compile(func_name + "\(" + func_current_param + "\)") print(p.match(inp).groups()) except: while 1: func_current_param += func_params_limiter + func_params_adder try: func_name = "([a-z-A-Z]+)\s*" p = re.compile(func_name + "\(" + func_current_param + "\)") print(p.match(inp).groups()) break except: pass
命令线路输入put:animalFunc
输出:('animalFunc','lion','tiger','giraffe','singe')
正如你所看到的,函数名永远是第一个在列表中,其余的是通过的参数名称
那么解析字符串和注释怎么样? – Qtax 2011-12-28 16:35:51
python不是一种常规的语言,所以你不能用正则表达式。 – 2011-12-28 16:43:05
@DouglasLeeder,正则表达式不正规。除非我们在这里讨论形式语言理论。 ;-) – Qtax 2011-12-28 16:46:13