ash*_*bar 1 python regex python-2.7
我编写了一个名为 that 的方法buildRegex,给定名称(类型为str),返回一个在模块中regex查找语句的对象。from ... import ... namePython
例如,以下是预期行为buildRegex:
>>> regObj = buildRegex('foo')
>>> regObj.search('from a import fool') is None
True
>>> regObj.search('from a import foo') is not None
True
>>> regObj.search('from a.b.c import foo as food') is None
True
>>> regObj.search('from a.b.c import fool, bar as foo') is not None
True
Run Code Online (Sandbox Code Playgroud)
到目前为止,我所掌握的内容适用于上面的所有示例(以及更多):
def buildRegex(name):
singleImportedName = r'(\b{0}\b(?!\s+as\s+))'.format(name)
importStatement = r'from\s+(\w+(\.\w+)*)\s+import\s+([^#\n]*)(?={0})'.format(singleImportedName )
return re.compile(importStatement)
Run Code Online (Sandbox Code Playgroud)
buildRegex假设搜索到的模块没有SyntaxErrors,这是可以的。
我的问题是,在查找导入的名称时foo,我还需要知道它是否是其他名称的别名。即如果一个模块有这样的语句:
from a.b.c import bar as foo
Run Code Online (Sandbox Code Playgroud)
我想知道什么foo是别名,在这种情况下,那就是bar. 目前,由于asserted lookaheads在正则表达式中,这是不可能的。所以,最后我的问题是:如何重构正则表达式以便这些信息不会丢失,即,如果给定的名称是别名,那么其别名的名称位于其中一个regex组中?
我建议不要编写复杂的正则表达式来解析导入,而是实际上使用将ast.parse源代码解析为抽象语法树并从那里找到名称,这样ast.parse可以保证正确解析Python。就像是:
import ast
class ImportFinder(ast.NodeVisitor):
def __init__(self):
self.imports = []
def visit_Import(self, node):
names = []
for i in node.names:
names.append((i.name, i.asname))
self.imports.append(['import', names])
def visit_ImportFrom(self, node):
module = node.module
level = node.level # how many dots
names = []
for i in node.names:
names.append((i.name, i.asname))
self.imports.append(('from', level, module, names))
def parse_imports(source):
tree = ast.parse(source)
finder = ImportFinder()
finder.visit(tree)
return finder.imports
Run Code Online (Sandbox Code Playgroud)
用法示例:
import pprint
pprint.pprint(parse_imports('''
from foo import bar, baz, frob
from .. import bar as spam, baz as ham, frob
import bar.baz
import bar.foo as baf
'''))
Run Code Online (Sandbox Code Playgroud)
打印出:
[('from', 0, 'foo', [('bar', None), ('baz', None), ('frob', None)]),
('from', 2, None, [('bar', 'spam'), ('baz', 'ham'), ('frob', None)]),
['import', [('bar.baz', None)]],
['import', [('bar.foo', 'baf')]]]
Run Code Online (Sandbox Code Playgroud)
行上的整数给出了模块名称之前from的编号。.