在Python中,如何捕获非捕获组中的组?换句话说,如何重复包含捕获组的非捕获子模式?
这样做的一个示例是捕获导入字符串上的所有包名称。例如。字符串:
导入pandas,os,sys
将返回' pandas',' os'和' sys'。以下模式捕获第一个包并进入第二个包:
import\s+([a-zA-Z0=9]*),*\s*
从这里开始,我想重复捕获该组并匹配以下字符的子模式,即([a-zA-Z0=9]*),*\s*
。当我用非捕获组围绕这个子模式并重复它时:
import\s+(?:([a-zA-Z0=9]*),*\s*)*
它不再捕获内部的组。
答案 0 :(得分:1)
你的问题严格地讲述了正则表达式,但是如果你愿意使用recursive descent parser(例如,pyparsing
),许多需要正则表达式专业知识的东西变得非常简单。
例如,这里你要问的是什么
last
这可能是个人品味的问题,但对我来说,
from pyparsing import *
p = Suppress(Literal('import')) + commaSeparatedList
>>> p.parseString('import pandas, os, sys').asList()
['pandas', 'os', 'sys']
>>> p.parseString('import pandas, os').asList()
['pandas', 'os']
也比正则表达式更直观。
答案 1 :(得分:0)
重复捕获组将仅捕获最后一次迭代。这就是为什么您需要重构正则表达式以使用re.findall
。
\s*
(?:
(?:^from\s+
( # Base (from (base) import ...)
(?:[a-zA-Z_][a-zA-Z_0-9]* # Variable name
(?:\.[a-zA-Z_][a-zA-Z_0-9]*)* # Attribute (.attr)
)
)\s+import\s+
)
|
(?:^import\s|,)\s*
)
( # Name of imported module (import (this))
(?:[a-zA-Z_][a-zA-Z_0-9]* # Variable name
(?:\.[a-zA-Z_][a-zA-Z_0-9]*)* # Attribute (.attr)
)
)
(?:
\s+as\s+
( # Variable module is imported into (import foo as bar)
(?:[a-zA-Z_][a-zA-Z_0-9]* # Variable name
(?:\.[a-zA-Z_][a-zA-Z_0-9]*)* # Attribute (.attr)
)
)
)?
\s*
(?=,|$) # Ensure there is another thing being imported or it is the end of string
捕获组0将是Base
,捕获组1将是(您所追求的)导入模块的名称,捕获组2将是模块所在的变量({{1 }})
from (group 0) import (group 1) as (group 2)
import re
regex = r"\s*(?:(?:^from\s+((?:[a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*))\s+import\s+)|(?:^import\s|,)\s*)((?:[a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*))(?:\s+as\s+((?:[a-zA-Z_][a-zA-Z_0-9]*(?:\.[a-zA-Z_][a-zA-Z_0-9]*)*)))?\s*(?=,|$)"
print(re.findall(regex, "import pandas, os, sys"))
如果您不关心其他两个捕获组,则可以将其删除。
答案 2 :(得分:0)
您可以使用import\s+(?:([a-zA-Z0-9=]+),*\s*)*
正则表达式(我只修复0-9
范围以匹配任何数字,并将=
包含在最后)并使用{{3}访问第1组捕获堆栈}}:
>>> import regex
>>> s = 'import pandas, os, sys'
>>> rx = regex.compile(r'^import\s+(?:([a-zA-Z0-9=]+),*\s*)*$')
>>> print([x.captures(1) for x in rx.finditer(s)])
[['pandas', 'os', 'sys']]