正则表达式捕获非捕获组内的组

时间:2016-09-09 17:32:13

标签: python regex

在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*)*

它不再捕获内部的组。

3 个答案:

答案 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

Try it on regex101.com

捕获组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']]