如何使用正则表达式捕获多个重复模式?

时间:2012-09-28 13:26:46

标签: python regex

我得到一些像这样的字符串:\input{{whatever}{1}}\mypath{{path1}{path2}{path3}...{pathn}}\shape{{0.2}{0.3}} 我想捕获所有路径:path1,path2,... pathn。我在python中尝试了re模块。但是,它不支持多次捕获。 例如:r"\\mypath\{(\{[^\{\}\[\]]*\})*\}"只会返回最后一个匹配的组。将模式应用于search(r"\mypath{{path1}{path2}})"只会将groups()作为("{path2}",)

返回

然后我找到了另一种方法:

    gpathRegexPat=r"(?:\\mypath\{)((\{[^\{\}\[\]]*\})*)(?:\})"
    gpathRegexCp=re.compile(gpathRegexPat)
    strpath=gpathRegexCp.search(r'\mypath{{sadf}{ad}}').groups()[0]
    >>> strpath
    '{sadf}{ad}'
    p=re.compile('\{([^\{\}\[\]]*)\}')
    >>> p.findall(strpath)
    ['sadf', 'ad']

或:

    >>> gpathRegexPat=r"\\mypath\{(\{[^{}[\]]*\})*\}"
    >>> gpathRegexCp=re.compile(gpathRegexPat, flags=re.I|re.U)
    >>> strpath=gpathRegexCp.search(r'\input{{whatever]{1}}\mypath{{sadf}{ad}}\shape{{0.2}{0.1}}').group()
    >>> strpath
    '\\mypath{{sadf}{ad}}'
    >>> p.findall(strpath)
    ['sadf', 'ad']

此时,我想,为什么不在原始字符串上使用findall?我可能会用: gpathRegexPat=r"(?:\\mypath\{)(?:\{[^\{\}\[\]]*\})*?\{([^\{\}\[\]]*)\}(?:\{[^\{\}\[\]]*\})*?(?:\})":如果第一个(?:\{[^\{\}\[\]]*\})*?匹配0次而第二个(?:\{[^\{\}\[\]]*\})*?匹配1次,则会捕获sadf;如果第一个(?:\{[^\{\}\[\]]*\})*?匹配1次,第二个匹配0次,它将捕获ad。但是,它只会使用此正则表达式返回['sadf']

没有所有这些额外的模式((?:\\mypath\{)(?:\})),它实际上有效:

    >>> p2=re.compile(r'(?:\{[^\{\}\[\]]*\})*?\{([^\{\}\[\]]*)\}(?:\{[^\{\}\[\]]*\})*?')
    >>> p2.findall(strpath)
    ['sadf', 'ad']
    >>> p2.findall('{adadd}{dfada}{adafadf}')
    ['adadd', 'dfada', 'adafadf']

任何人都可以向我解释这种行为吗?有没有更聪明的方法来实现我想要的结果?

2 个答案:

答案 0 :(得分:1)

你是对的。无法在组内返回重复的子组。要执行所需操作,可以使用正则表达式捕获组,然后使用第二个正则表达式捕获重复的子组。

在这种情况下,类似于:\\mypath{(?:\{.*?\})}。这将返回{path1}{path2}{path3}

然后要在该字符串中找到{pathn}的重复模式,您只需使用\{(.*?)\}即可。这将匹配任何与括号。 .*?.*的非贪婪版本,这意味着它将返回最短的匹配,而不是最长的匹配。

答案 1 :(得分:1)

re.findall("{([^{}]+)}",text)

应该有效

返回

['path1', 'path2', 'path3', 'pathn']

终于

my_path = r"\input{{whatever}{1}}\mypath{{path1}{path2}{path3}...{pathn}}\shape{{0.2}{0.3}}"
#get the \mypath part
my_path2 = [p for p in my_path.split("\\") if p.startswith("mypath")][0]
print re.findall("{([^{}]+)}",my_path2)

甚至更好

re.findall("{(path\d+)}",text) #will only return things like path<num> inside {}