从Python代码字符串(regex或AST)中提取所有变量

从Python代码字符串(regex或AST)中提取所有变量,python,regex,abstract-syntax-tree,Python,Regex,Abstract Syntax Tree,我想找到并提取包含Python代码的字符串中的所有变量。我只想提取变量(以及带有下标的变量),但不想提取函数调用 例如,从以下字符串: code = 'foo + bar[1] + baz[1:10:var1[2+1]] + qux[[1,2,int(var2)]] + bob[len("foobar")] + func() + func2 (var3[0])' 我想提取:foo,bar[1],baz[1:10:var1[2+1],var1[2+1],qux[[1,2,int(var2)],v

我想找到并提取包含Python代码的字符串中的所有变量。我只想提取变量(以及带有下标的变量),但不想提取函数调用

例如,从以下字符串:

code = 'foo + bar[1] + baz[1:10:var1[2+1]] + qux[[1,2,int(var2)]] + bob[len("foobar")] + func() + func2 (var3[0])'
我想提取:
foo
bar[1]
baz[1:10:var1[2+1]
var1[2+1]
qux[[1,2,int(var2)]
var2
bob[len(“foobar”)]
var3[0]
。请注意,某些变量可能是“嵌套的”。例如,我想从
baz[1:10:var1[2+1]]
中提取
baz[1:10:var1[2+1]
var1[2+1]

首先想到的两个想法是使用正则表达式或AST。我两个都试过了,但都没有成功

在使用正则表达式时,为了使事情更简单,我认为最好先提取“顶级”变量,然后递归地提取嵌套的变量。不幸的是,我甚至不能这样做

这就是我到目前为止所做的:

regex = r'[_a-zA-Z]\w*\s*(\[.*\])?'
for match in re.finditer(regex, code):
    print(match)
下面是一个演示:

另一种解决方案是使用AST,扩展
AST.NodeVisitor
,并实现
visit\u Name
visit\u Subscript
方法。但是,这也不起作用,因为函数也会调用
visit\u Name

如果有人能为我提供这个问题的解决方案(regex或AST),我将不胜感激


谢谢。

正则表达式不是一个足够强大的工具来实现这一点。如果有一个有限的嵌套深度,有一些黑客的工作,这将允许您使复杂的正则表达式做什么,你正在寻找,但我不推荐它


如果您真的必须为代码解析字符串,那么AST在技术上是可行的,但我不知道有哪一个库可以提供帮助。您最好尝试构建一个递归函数来进行解析。

我发现您的问题是一个有趣的挑战,因此这里有一个代码可以实现您想要的功能,仅使用
Regex
就可以做到这一点。这是不可能的,因为存在嵌套表达式,这是一个结合使用
Regex
和字符串操作来处理嵌套表达式的解决方案:

#-*-编码:utf-8-*-
进口稀土
RE\u IDENTIFIER=r'\b[a-z]\w*\b(?!\s*[\[\(“\'])”
RE#u INDEX_ONLY=RE.compile(r'(##)(\d+)(##)'))
RE#u INDEX=RE.compile(“##\d+##”)
def extract_表达式(字符串):
“”“按给定顺序提取所有标识符和getitem表达式。”“”
def删除括号(文本):
#1.句柄“[…]”表达式将它们替换为#{#……#}#
#所以我们不会把它们和[…]这个词混淆

pattern='(?普通正则表达式肯定不能做到这一点,因为不可能编写一个正则表达式来匹配所有形式的
foo][[][[0][[0]]]]]
。对我来说,专注于基于AST的解决方案似乎是个好主意。”
函数也需要访问\u Name
“-函数名也是变量。这里的目标是什么?@Kevin我在想,所以我想我可以只匹配第一对外括号,然后继续应用正则表达式。例如,如果我有这个
foo[bar[baz[0]]]+10
,我想提取
foo[bar[baz[0]]
。然后,我可以使用一些基本的字符串操作并隔离下标:
bar[baz[0]]
。然后我可以再次应用正则表达式,依此类推。但如果你不愿意这样做,那么我想我必须使用ASTs!@jornsharpe这有点难以完全解释,但非常简单:我正在编写一个软件,用户可以输入自己的python表达式并将其分配给“参数”指数学模型。这些参数也可以作为变量出现在表达式中。因此,我们最终得到依赖于其他参数的参数。我的目标是解析所有Python表达式,提取所有变量(参数),并创建一个包含所有参数的依赖关系树。使用此信息,我可以执行拓扑排序,以正确的顺序计算表达式。我想知道您是否最好只从表达式中提取每个名称,并通过将每个名称与whitelis进行比较来区分参数名称和函数名称t个已批准的函数名。在评估用户输入时,通常最好限制它们可以调用的内容。(请注意,这并不足以完全保护您的环境,但会有所帮助)哇!我不得不说我印象深刻!非常有趣的解决方案,你的评论真的有助于理解发生了什么!谢谢我的朋友!
['foo', 'bar[1]', 'baz[1:10:var1[2+1]]', 'var1[2+1]', 'qux[[1,2,int(var2)]]', 'var2', 'bob[len("foobar")]', 'var3[0]']
['baz[1:10:var1[2+1]]', 'var1[2+1]']
['baz[[1]:10:var1[2+1]:[var3[3+1*x]]]', 'var1[2+1]', 'var3[3+1*x]', 'x']