正则表达式中带括号的Ifthen&lookahead

2024-05-16 02:02:14 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个小项目,涉及grepping通过.py文件和挑选导入语句的形式只有from <x> import <y>。你知道吗

在构建正则表达式以捕获这一点时,涉及到两种不同的语法,最好通过示例加以说明:

语法#1使用括号,并且可以在括号中包含换行符:

from .sql.base import (
    SchemaVisitor
    )
import os  # ignore this import
from _pytest.config import (
    main, UsageError, cmdline,
    hookspec, hookimpl
)

我可以用以下方法捕捉到:

syntax1 = re.compile(r'^ *from (?P<package>[.\w]+) +import +\(?(?P<objects>[*, \n\w]+)\)? *$',
                     flags=re.MULTILINE)

语法#2使用行连续体(如果需要),从技术上讲,import语句中没有换行:

from pandas import Series

from .solvers import solve, solve_linear_system, solve_linear_system_LU, \
    solve_undetermined_coeffs, nsolve, solve_linear, checksol, \
    det_quick, inv_quick, check_assumptions

from .ode import checkodesol, classify_ode, dsolve, \
    homogeneous_order

我可以用以下方法捕捉到:

# Only difference: no `\n` in <objects> group
syntax2 = re.compile(r'^ *from (?P<package>[.\w]+) +import +(?P<objects>[*, \w]+) *$',
                     flags=re.MULTILINE)

我想把这些压缩成一个语句,能够一次压缩所有命名的组。你知道吗

我在这里需要的是一个if-then条件,带有一个积极的前瞻性。类似于:

syntax = re.compile(r'^ *from (?P<package>[.\w]+) +import +(?(?=\([^)]+\))\((?P<obj1>[*, \n\w]+)\) *$|(?P<obj2>[*, \w]+) *$)',
                    flags=re.MULTILINE)

这似乎遵循(?ifthen|else)的语法,并对if进行了展望,即

(?(?=regex)then|else)

其中:

  • if(?=\([^)]+\)):括号中包含一些不是括号的文本
  • then\((?P<obj1>[*, \n\w]+)\) *$
  • else(?P<obj2>[*, \w]+) *$)

我这里怎么了?你知道吗

输入:

imports = """
from .sql.base import (
    SchemaVisitor
    )

from pandas import Series as ser, DataFrame as df
from NumPy import array

import os
import functools

import ctypes  # ignore these

from _pytest.config import (
    main, UsageError, cmdline,
    hookspec, hookimpl
)

from .solvers import solve, solve_linear_system, solve_linear_system_LU, \
    solve_undetermined_coeffs, nsolve, solve_linear, checksol, \
    det_quick, inv_quick, check_assumptions

from .ode import checkodesol, classify_ode, dsolve, \
    homogeneous_order
"""

期望结果:

syntax.findall(imports)

[('.sql.base', '\n    SchemaVisitor\n    '),
 ('pandas', 'Series\n'),
 ('_pytest.config', '\n    main, UsageError, cmdline,\n    hookspec, hookimpl\n'),
 ('.solvers', 'solve, solve_linear_system, solve_linear_system_LU,     solve_undetermined_coeffs, nsolve, solve_linear, checksol,     det_quick, inv_quick, check_assumptions\n'),
 ('.ode', 'checkodesol, classify_ode, dsolve,     homogeneous_order\n')]

Tags: fromimportresqlbasepytest语法语句
2条回答

你可以用

import re

rx = re.compile(r'''
    ^\ *from\s+
    (?P<package_name>[.\w]+)\s+
    import\s+
    (\()?
    (?(2)
        (?P<object>[^()]+)\)
        |
        (?P<object2>(?:.+[\n\r]?)+)
    )
''', re.VERBOSE | re.MULTILINE)

def aftermatch(group1, group2):
    group = group1 if group1 else group2
    objects = [obj.strip() for obj in group.split(',')]
    return objects

packages = {m.group('package_name'): aftermatch(m.group('object'), m.group('object2'))
            for m in rx.finditer(data)}
print(packages)


它为字符串imports生成:
{'.sql.base': ['SchemaVisitor'], 'pandas': ['Series'], '_pytest.config': ['main', 'UsageError', 'cmdline', 'hookspec', 'hookimpl'], '.solvers': ['solve', 'solve_linear_system', 'solve_linear_system_LU', 'solve_undetermined_coeffs', 'nsolve', 'solve_linear', 'checksol', 'det_quick', 'inv_quick', 'check_assumptions'], '.ode': ['checkodesol', 'classify_ode', 'dsolve', 'homogeneous_order']}


有关regex101.com上的表达式,请参见一个演示,其余部分是一个dict理解,它使用了一个名为aftermatch()的函数来清理对象部分。


编辑:对于非粘滞者,可以使用支持分支重置的较新的^{} module。在这里,您不再需要函数:
import regex as re
rx = re.compile(r'''
    ^from\s+
    (?P<package_name>[.\w]+)\s+
    import\s+
    (?|
        \((?P<object>[^()]+)\)
        |   
        (?P<object>(?:.+[\n\r]?)+)
    )
''', re.VERBOSE | re.MULTILINE)

packages = {m.group('package_name'): 
            [obj.strip() for obj in m.group('object').split(',')]
            for m in rx.finditer(imports)}
print(packages)

if-else功能在技术上是可行的,您只需要用“|”语句来考虑它。你知道吗

^ *from (?P<package>[.\w]+) +import (\()?(?(2)(?P<object0>[*, \n\w]+)\)|(?P<object1>[*, \w]+))

如果|之前的表达式不匹配,则选择|之后的表达式。实际上,如果在语句的then部分包含if,那么这本质上就是if-then-else。你知道吗

相关问题 更多 >