If-then & 在正则表达式中用括号向前看
If-then & lookahead with parentheses in regex
我有一个小项目,涉及 grepping through .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 使用换行符(如果需要),技术上在导入语句中没有换行符:
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')]
if else 功能在技术上是可行的,您只需要根据“|”来考虑它声明。
^ *from (?P<package>[.\w]+) +import (\()?(?(2)(?P<object0>[*, \n\w]+)\)|(?P<object1>[*, \w]+))
如果|之前的表达式不匹配则 select| 之后的表达式。实际上,如果您将 if 包含在语句的 then 部分中,这本质上就是一个 if then else。
你可以使用
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 上表达式的演示,其余部分是一个字典理解,带有一个名为 aftermatch()
的函数,用于随后清理对象部分。
编辑: 对于 non-sticklers,您可以使用支持分支重置的较新的 regex
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)
我有一个小项目,涉及 grepping through .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 使用换行符(如果需要),技术上在导入语句中没有换行符:
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')]
if else 功能在技术上是可行的,您只需要根据“|”来考虑它声明。
^ *from (?P<package>[.\w]+) +import (\()?(?(2)(?P<object0>[*, \n\w]+)\)|(?P<object1>[*, \w]+))
如果|之前的表达式不匹配则 select| 之后的表达式。实际上,如果您将 if 包含在语句的 then 部分中,这本质上就是一个 if then else。
你可以使用
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 上表达式的演示,其余部分是一个字典理解,带有一个名为
aftermatch()
的函数,用于随后清理对象部分。
编辑: 对于 non-sticklers,您可以使用支持分支重置的较新的
regex
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)