正则表达式: 如何在正则表达式中捕获可选捕获组后面的一个组?

5
假设我有以下字符串:
s1=u'--FE(-)---'
s2=u'--FEM(-)---'
s3=u'--FEE(--)-'

我希望能够将 F,E,E,M 和括号中的内容分成不同的组。

我尝试了以下正则表达式:

u'^.-([F])([EF]*)([E]+)[^FEM]?(M*)?(\\(.*\\))?.*$'

这个表达式针对不同的字符串给出以下分组和范围:

s1 -> 'F',(2,3)   ,   '',(3,3)    ,    'E',(3,4)    ,    '',(5,5)    ,    None,(-1,-1)
s2 -> 'F',(2,3)   ,   '',(3,3)    ,    'E',(3,4)    ,    'M',(4,5)   ,    (-),(5,8)
s3 -> 'F',(2,3)   ,   'E',(3,4)   ,    'E',(4,5)    ,    '',(6,6)    ,    None,(-1,-1)

对于s2,我得到了想要的行为,即括号内容的匹配,但对于s1和s3却没有。

我该如何创建一个正则表达式,以便匹配括号中的内容,即使我没有一个包含'M'的正确匹配组?

编辑:

DWilches的答案使用了正则表达式解决了最初的问题。

'^.-(F)([EF]*)(E+)[^FEM]??(M*)(\(.*\)).*?$'

然而,括号组也是可选的。下面的简短 Python 脚本阐明了这个问题:

s1=u'--FE(-)---'
s2=u'--FEM(-)--'
s3=u'--FEE(--)-'
s4=u'--FEE-M(---)--'
s5=u'--FE-M-(-)-'
s6=u'--FEM--'
s7=u'--FE-M--'

ll=[s1,s2,s3,s4,s5,s6,s7]

import re
rr1=re.compile(u'^.-(F)([EF]*)(E+)[^FEM]??(M*)[^FEM]??(\(.*\)).*?$')
rr2=re.compile(u'^.-(F)([EF]*)(E+)[^FEM]??(M*)[^FEM]??(\(.*\))?.*?$')

for s in ll:
    b=rr1.search(s)
    print s
    if b:
        print " '%s' '%s' '%s' '%s' '%s' " % (b.group(1), b.group(2), b.group(3),     b.group(4), b.group(5))
    else:
        print 'No match'
    print '######'

对于rr1,输出结果为:
--FE(-)---
 'F' '' 'E' '' '(-)' 
######
--FEM(-)--
 'F' '' 'E' 'M' '(-)' 
######
--FEE(--)-
 'F' 'E' 'E' '' '(--)' 
######
--FEE-M(---)--
 'F' 'E' 'E' 'M' '(---)' 
######
--FE-M-(-)-
 'F' '' 'E' 'M' '(-)' 
######
--FEM--
No match
######
--FE-M--
No match
######

前五个字符串是可以的,但对于最后两个字符串不行,因为它需要括号。

然而,对于rr2,在(\(.*\))后面添加?,会产生以下输出:

--FE(-)---
 'F' '' 'E' '' '(-)' 
######
--FEM(-)--
 'F' '' 'E' 'M' '(-)' 
######
--FEE(--)-
 'F' 'E' 'E' '' '(--)' 
######
--FEE-M(---)--
 'F' 'E' 'E' '' 'None' 
######
--FE-M-(-)-
 'F' '' 'E' '' 'None' 
######
--FEM--
 'F' '' 'E' 'M' 'None' 
######
--FE-M--
 'F' '' 'E' '' 'None' 
######

对于 s1,s2,s3s6,这是可以的。

需要进行一些修改才能得到所需的输出结果:如果存在,则获取 M,并获取括号内的内容。

1个回答

3

看起来你需要使用非贪婪操作符:

^.-(F)([EF]*)(E+)[^FEM]??(M*)(\\(.*\\))?.*?$

请注意在最后一个 .* 后我添加了 ?。同时我也将 [^FEM]? 改为了 [^FEM]??
在你提供的第一个示例中,问题出在最后一个 .*-) 匹配到了,而你的 [^FEM]? 却匹配到了 (,因此没有留下任何内容给 (\\(.*\\))?
(我还删除了一些单个字母周围的方括号,但这只是为了让正则表达式更短)
使用这个正则表达式,我得到了以下结果:
--FE(-)---    ->     'F'    ''     'E'    ''     '(-)'
--FEM(-)---   ->     'F'    ''     'E'    'M'    '(-)'
--FEE(--)-    ->     'F'    'E'    'E'    ''     '(--)'

顺便说一下:我还会删除(\\(.*\\))?末尾的?,因为即使您没有将其放在那里,不匹配该部分的字符串也将被后面的.*?消耗掉。


这就是问题所在。 开始的括号被 [^FEM]? 消耗掉,剩下的字符串被 .* 结尾。 - sharcashmo
这在某种程度上有所帮助。然而,该表达式无法解决像--FEE-M(--)--或--FEM-(-)-这样的问题。 - Erlend Aune
在我的测试中,使用模式 --FEE-M(--)-- 会产生以下结果:'F' 'E' 'E' 'M' '(--)'。那么预期的输出是什么? - Daniel
奇怪。对我来说不是这样。您正在使用Python吗?如果是,您是否使用任何标志?对我来说,--FEE-M(--)--产生了'F','E','E','','' - Erlend Aune
是的,我正在使用Python,没有特殊标志。这是我的代码:m = re.search('^.-(F)([EF]*)(E+)[^FEM]??(M*)(\(.*\)).*?$', '--FEE-M(--)--') print " '%s' '%s' '%s' '%s' '%s' " % (m.group(1), m.group(2), m.group(3), m.group(4), m.group(5)) - Daniel
似乎在(\(.*\))?中加入?有所不同。我已经更新了初始帖子。 - Erlend Aune

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接