匹配最后一个(可能是嵌套的)括号组

3
我想匹配最后一个被包含在[]中的组,但它本身可能包含一个或多个嵌套的[]。我使用Pythonregex解决了嵌套的[]匹配问题,虽然不够优雅。这个解决方案对于某些情况(如s1)有效,但是当有多个这样的匹配时,对于s2s3无效。我的解决方案只会匹配第一个。有什么建议吗?是否需要更好的正则表达式?或者说正则表达式不是解决这个问题的方法?非常感谢!
In [116]:

s1 = 'AAA [BBB [CCC]]'
s2 = 'AAA [DDD] [EEE]'
s3 = 'AAA [BBB [CCC]] [EEE]'

for s in [s1, s2, s3]:
    result = regex.search(r'(?<rec>\[(?:[^\[\]]++|(?&rec))*\])',s,flags=regex.VERBOSE)
    print(result.captures('rec'))
['[CCC]', '[BBB [CCC]]'] #I know it is perfect, but I can take the last one in the list
['[DDD]'] #This is the first one, I want the last one, which is [EEE]
['[CCC]', '[BBB [CCC]]'] #same problem as above

编辑:

非常感谢帮助,如果我有15个声望值,我会给你们所有人点赞。但是,很抱歉没有包括预期的结果,应该是:

'AAA [BBB [CCC]]' -> '[BBB [CCC]]'
'AAA [DDD] [EEE]' -> '[EEE]'
'AAA [BBB [CCC]] [EEE]' -> '[EEE]'
'000 [[aaa] xxx [yyy [zzz ]]' -> '[[aaa] xxx [yyy [zzz ]]'

事实上,你可以使用向前/向后查找来完成这个任务。然而,在这种情况下,我可能会使用堆栈/解析器。 - SystemFun
1
@Vlad,他有一个嵌套结构。这可能是为什么他在这里使用递归正则表达式的原因,我不确定仅仅使用look around是否足够,如果我错了,请纠正我。欢迎来到SO,OP! - CT Zhu
你想要什么输出? - Padraic Cunningham
FYI,已添加测试过的Python代码。 :) - zx81
@CTZhu,你提出了一个很好的观点,但是000 [[aaa] xxx [yyy [zzz ]]应该产生[[aaa] xxx [yyy [zzz ]],请参见编辑: - user3732025
显示剩余2条评论
3个回答

3
在Python中,要使用递归或重复子程序,我们需要使用Matthew Barnett的出色正则表达式模块... 正如@CTZhu指出的那样,您已经在使用它!
明确术语,"嵌套"可以有几种理解,例如:
1. "简单嵌套",如[C[D[E]F]],是一个子集... 2. "更复杂的家庭式嵌套",如[B[C] [D] [E[F][G]]]
您需要能够处理后者,这个简短的正则表达式就可以做到:
\[(?:[^[\]]++|(?R))*\]

这将匹配所有嵌套的大括号。现在我们只需要打印最后一个匹配项。 以下是经过测试的Python代码:
import regex # say "yeah!" for Matthew Barnett
pattern = r'\[(?:[^[\]]++|(?R))*\]'
myregex = regex.compile(pattern)

# this outputs [EEE]
matches = myregex.findall('AAA [BBB [CCC]] [EEE]')
print (matches[-1])

# this outputs [C[D[E]F]] (simple nesting)
matches = myregex.findall('AAA [BBB] [C[D[E]F]]')
print (matches[-1])

# this outputs [B[C] [D] [E[F][G]]] (family-style nesting)
matches = myregex.findall('AAA [AAA] [B[]B[B]] [B[C] [D] [E[F][G]]]')
print (matches[-1])

+1 给(我认为的)正确答案。但你错过了一个事实,即 OP 已经在使用 regex,看到 regex.search 了吗?干杯! - CT Zhu
非常感谢您提供的完美解决方案!我会学习您提供的演示来更好地理解它。 - user3732025
@user3732025,感谢您提出这个好问题,希望再次见到您! :) - zx81
很棒的解决方案!但是你不需要使用 matches[len(matches)-1],只需使用 matches[-1] 来获取最后一个元素,使用 matches[-2] 获取倒数第二个元素,以此类推。 - dawg
@dawg 确实!你可以看到我仍在学习Python。非常感谢,已经进行了编辑,这是个进步。 :) - zx81
显示剩余5条评论

2
您可以使用这个递归正则表达式,并只打印最后一次匹配:
s1 = 'AAA [BBB [CCC]]'
s2 = 'AAA [DDD] [EEE]'
s3 = 'AAA [BBB [CCC]] [EEE]'

import regex

for e in (s1, s2, s3):
    matches=regex.findall(r'[^\[\]\s]+ | \[ (?: (?R) | [^\[\]]+ )+\]', e, regex.VERBOSE)
    print(e, '=>', matches, '=>', matches[-1])

输出:

AAA [BBB [CCC]] => ['AAA', '[BBB [CCC]]'] => [BBB [CCC]]
AAA [DDD] [EEE] => ['AAA', '[DDD]', '[EEE]'] => [EEE]
AAA [BBB [CCC]] [EEE] => ['AAA', '[BBB [CCC]]', '[EEE]'] => [EEE]

非常感谢。实际上,这与预期结果有些不同,@zx81已经提供了一个很好的解决方案。 - user3732025

1

根据你提供的数据,并且你表示想要最后一组,我将为你提供这个递归正则表达式。

import regex

s1 = 'AAA [BBB [CCC]]'
s2 = 'AAA [DDD] [EEE]'
s3 = 'AAA [BBB [CCC]] [EEE]'

for s in [s1, s2, s3]:
    result = regex.findall(r'\[(?:[^[\]]|(?R))*\]', s)
    print result[-1]

输出

[BBB [CCC]]
[EEE]
[EEE]

非常感谢。但请查看我的编辑以获取预期结果。干杯! - user3732025

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